triangle_mesh.template.cc
Go to the documentation of this file.
1 //LIC// ====================================================================
2 //LIC// This file forms part of oomph-lib, the object-oriented,
3 //LIC// multi-physics finite-element library, available
4 //LIC// at http://www.oomph-lib.org.
5 //LIC//
6 //LIC// Copyright (C) 2006-2021 Matthias Heil and Andrew Hazel
7 //LIC//
8 //LIC// This library is free software; you can redistribute it and/or
9 //LIC// modify it under the terms of the GNU Lesser General Public
10 //LIC// License as published by the Free Software Foundation; either
11 //LIC// version 2.1 of the License, or (at your option) any later version.
12 //LIC//
13 //LIC// This library is distributed in the hope that it will be useful,
14 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 //LIC// Lesser General Public License for more details.
17 //LIC//
18 //LIC// You should have received a copy of the GNU Lesser General Public
19 //LIC// License along with this library; if not, write to the Free Software
20 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 //LIC// 02110-1301 USA.
22 //LIC//
23 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24 //LIC//
25 //LIC//====================================================================
26 #ifndef OOMPH_TRIANGLE_MESH_TEMPLATE_CC
27 #define OOMPH_TRIANGLE_MESH_TEMPLATE_CC
28 
29 #include <iostream>
30 
31 #include "triangle_mesh.template.h"
32 #include "../generic/map_matrix.h"
33 #include "../generic/multi_domain.h"
34 #include "../generic/projection.h"
35 #include "../generic/face_element_as_geometric_object.h"
36 
37 namespace oomph
38 {
39 
40  //======================================================================
41  /// Build with the help of the scaffold mesh coming
42  /// from the triangle mesh generator Triangle.
43  //======================================================================
44  template<class ELEMENT>
45  void TriangleMesh<ELEMENT>::build_from_scaffold(TimeStepper* time_stepper_pt,
46  const bool &use_attributes)
47  {
48  // Mesh can only be built with 2D Telements.
49  MeshChecker::assert_geometric_element<TElementGeometricBase,ELEMENT>(2);
50 
51  // Create space for elements
52  unsigned nelem = Tmp_mesh_pt->nelement();
53  Element_pt.resize(nelem);
54 
55  // Create space for nodes
56  unsigned nnode_scaffold = Tmp_mesh_pt->nnode();
57 
58  // Create a map storing the node_id of the mesh used to update the
59  // node position in the update_triangulateio function
60  std::map<Node*, unsigned> old_global_number;
61 
62  // Store the TriangulateIO node id
63  for (unsigned inod = 0; inod < nnode_scaffold; inod++)
64  {
65  Node* old_node_pt = Tmp_mesh_pt->node_pt(inod);
66  old_global_number[old_node_pt] = inod;
67  }
68 
69  // Initialize the old node id vector
70  Oomph_vertex_nodes_id.resize(nnode_scaffold);
71 
72  // Create space for nodes
73  Node_pt.resize(nnode_scaffold, 0);
74 
75  // Set number of boundaries
76  unsigned nbound = Tmp_mesh_pt->nboundary();
77 
78  // Resize the boundary information
79  set_nboundary(nbound);
80  Boundary_element_pt.resize(nbound);
81  Face_index_at_boundary.resize(nbound);
82 
83  //If we have different regions, then resize the region
84  //information
85  if (use_attributes)
86  {
87  Boundary_region_element_pt.resize(nbound);
88  Face_index_region_at_boundary.resize(nbound);
89  }
90 
91  // Loop over elements in scaffold mesh, visit their nodes
92  for (unsigned e = 0; e < nelem; e++)
93  {
94  Element_pt[e] = new ELEMENT;
95  }
96 
97  //Number of nodes per element from the scaffold mesh
98  unsigned nnod_el = Tmp_mesh_pt->finite_element_pt(0)->nnode();
99 
100  // Setup map to check the (pseudo-)global node number
101  // Nodes whose number is zero haven't been copied across
102  // into the mesh yet.
103  std::map<Node*, unsigned> global_number;
104  unsigned global_count = 0;
105 
106  // Map of Element attribute pairs
107  std::map<double, Vector<FiniteElement*> > element_attribute_map;
108 
109  // If we're using attributes
110  if (use_attributes)
111  {
112  // If we're using attributes then we need attribute 0 which will
113  // be associated with region 0
114  element_attribute_map[0].resize(0);
115  }
116 
117  // Loop over elements in scaffold mesh, visit their nodes
118  for (unsigned e = 0; e < nelem; e++)
119  {
120  // Loop over all nodes in element
121  for (unsigned j = 0; j < nnod_el; j++)
122  {
123  // Pointer to node in the scaffold mesh
124  Node* scaffold_node_pt = Tmp_mesh_pt->finite_element_pt(e)->node_pt(j);
125 
126  // Get the (pseudo-)global node number in scaffold mesh
127  // (It's zero [=default] if not visited this one yet)
128  unsigned j_global = global_number[scaffold_node_pt];
129 
130  // Haven't done this one yet
131  if (j_global == 0)
132  {
133  // Find and store the node_id in the old nodes map
134  Oomph_vertex_nodes_id[global_count] =
135  old_global_number[scaffold_node_pt];
136 
137  // Get pointer to set of mesh boundaries that this
138  // scaffold node occupies; NULL if the node is not on any boundary
139  std::set<unsigned>* boundaries_pt;
140  scaffold_node_pt->get_boundaries_pt(boundaries_pt);
141 
142  //Storage for the new node
143  Node* new_node_pt = 0;
144 
145  //Is it on boundaries
146  if (boundaries_pt != 0)
147  {
148  //Create new boundary node
149  new_node_pt=
150  finite_element_pt(e)->construct_boundary_node(j,time_stepper_pt);
151 
152  // Add to boundaries
153  for (std::set<unsigned>::iterator it = boundaries_pt->begin(); it
154  != boundaries_pt->end(); ++it)
155  {
156  add_boundary_node(*it, new_node_pt);
157  }
158  }
159  //Build normal node
160  else
161  {
162  //Create new normal node
163  new_node_pt = finite_element_pt(e)->construct_node(j,time_stepper_pt);
164  }
165 
166  // Give it a number (not necessarily the global node
167  // number in the scaffold mesh -- we just need something
168  // to keep track...)
169  global_count++;
170  global_number[scaffold_node_pt] = global_count;
171 
172  // Copy new node, created using the NEW element's construct_node
173  // function into global storage, using the same global
174  // node number that we've just associated with the
175  // corresponding node in the scaffold mesh
176  Node_pt[global_count - 1] = new_node_pt;
177 
178  // Assign coordinates
179  for (unsigned i = 0; i < finite_element_pt(e)->dim(); i++)
180  {
181  new_node_pt->x(i) = scaffold_node_pt->x(i);
182  }
183  }
184  // This one has already been done: Copy accross
185  else
186  {
187  finite_element_pt(e)->node_pt(j) = Node_pt[j_global - 1];
188  }
189  }
190 
191  // If we're using attributes
192  if (use_attributes)
193  {
194  element_attribute_map[Tmp_mesh_pt->element_attribute(e)].push_back(
195  finite_element_pt(e));
196  }
197  }
198 
199  //Now let's construct lists
200  //Find the number of attributes
201  if (use_attributes)
202  {
203  unsigned n_attribute = element_attribute_map.size();
204 
205  //There are n_attribute different regions
206  this->Region_attribute.resize(n_attribute);
207 
208  //Copy the vectors in the map over to our internal storage
209  unsigned count = 0;
210  for (std::map<double, Vector<FiniteElement*> >::iterator it =
211  element_attribute_map.begin(); it!=element_attribute_map.end(); ++it)
212  {
213  this->Region_attribute[count] = it->first;
214  Region_element_pt[static_cast<unsigned>(Region_attribute[count])] =
215  it->second;
216  ++count;
217  }
218 
219  }
220 
221  // At this point we've created all the elements and
222  // created their vertex nodes. Now we need to create
223  // the additional (midside and internal) nodes!
224 
225  unsigned boundary_id=0;
226 
227  // Get number of nodes along element edge and dimension of element (2)
228  // from first element
229  unsigned n_node_1d = finite_element_pt(0)->nnode_1d();
230  unsigned dim = finite_element_pt(0)->dim();
231 
232  // Storage for the local coordinate of the new node
233  Vector<double> s(dim);
234 
235  // Get number of nodes in the element from first element
236  unsigned n_node = finite_element_pt(0)->nnode();
237 
238  //Storage for each global edge of the mesh
239  unsigned n_global_edge = Tmp_mesh_pt->nglobal_edge();
240  Vector < Vector<Node*> > nodes_on_global_edge(n_global_edge);
241 
242  // Loop over elements
243  for (unsigned e = 0; e < nelem; e++)
244  {
245  //Cache pointers to the elements
246  FiniteElement* const elem_pt = finite_element_pt(e);
247  FiniteElement* const tmp_elem_pt = Tmp_mesh_pt->finite_element_pt(e);
248 
249  //The number of edge nodes is 3*(nnode_1d-1)
250  unsigned n_edge_node = 3 * (n_node_1d - 1);
251 
252  //If there are any more nodes, these are internal and can be
253  //constructed and added directly to the mesh
254  for (unsigned n = n_edge_node; n < n_node; ++n)
255  {
256  // Create new node (it can never be a boundary node)
257  Node* new_node_pt = elem_pt->construct_node(n, time_stepper_pt);
258 
259  // What are the node's local coordinates?
260  elem_pt->local_coordinate_of_node(n, s);
261 
262  // Find the coordinates of the new node from the existing
263  // and fully-functional element in the scaffold mesh
264  for (unsigned i = 0; i < dim; i++)
265  {
266  new_node_pt->x(i) = tmp_elem_pt->interpolated_x(s, i);
267  }
268 
269  //Add the node to the mesh's global look-up scheme
270  Node_pt.push_back(new_node_pt);
271  }
272 
273  //Now loop over the mid-side edge nodes
274  //Start from node number 3
275  unsigned n = 3;
276 
277  // Loop over edges
278  for (unsigned j = 0; j < 3; j++)
279  {
280  //Find the boundary id of the edge
281  boundary_id = Tmp_mesh_pt->edge_boundary(e, j);
282 
283  //Find the global edge index
284  unsigned edge_index = Tmp_mesh_pt->edge_index(e, j);
285 
286  //If the nodes on the edge have not been allocated, construct them
287  if (nodes_on_global_edge[edge_index].size() == 0)
288  {
289  //Loop over the nodes on the edge excluding the ends
290  for (unsigned j2 = 0; j2 < n_node_1d - 2; ++j2)
291  {
292  //Storage for the new node
293  Node* new_node_pt = 0;
294 
295  //If the edge is on a boundary, construct a boundary node
296  if (boundary_id > 0)
297  {
298  new_node_pt = elem_pt->construct_boundary_node(n, time_stepper_pt);
299  //Add it to the boundary
300  this->add_boundary_node(boundary_id - 1, new_node_pt);
301  }
302  //Otherwise construct a normal node
303  else
304  {
305  new_node_pt = elem_pt->construct_node(n, time_stepper_pt);
306  }
307 
308  // What are the node's local coordinates?
309  elem_pt->local_coordinate_of_node(n, s);
310 
311  // Find the coordinates of the new node from the existing
312  // and fully-functional element in the scaffold mesh
313  for (unsigned i = 0; i < dim; i++)
314  {
315  new_node_pt->x(i) = tmp_elem_pt->interpolated_x(s, i);
316  }
317 
318  //Add to the global node list
319  Node_pt.push_back(new_node_pt);
320 
321  //Add to the edge index
322  nodes_on_global_edge[edge_index].push_back(new_node_pt);
323  //Increment the node number
324  ++n;
325  }
326  }
327  //Otherwise just set the pointers
328  //using the fact that the next time the edge is visited
329  //the nodes must be arranged in the other order because all
330  //triangles have the same orientation
331  else
332  {
333  //Loop over the nodes on the edge excluding the ends
334  for (unsigned j2 = 0; j2 < n_node_1d - 2; ++j2)
335  {
336  //Set the local node from the edge but indexed the other
337  //way around
338  elem_pt->node_pt(n) = nodes_on_global_edge[edge_index][n_node_1d - 3
339  - j2];
340  ++n;
341  }
342  }
343 
344  //Set the elements adjacent to the boundary from the
345  //boundary id information
346  if (boundary_id > 0)
347  {
348  Boundary_element_pt[boundary_id - 1].push_back(elem_pt);
349  //Need to put a shift in here because of an inconsistent naming
350  //convention between triangle and face elements
351  Face_index_at_boundary[boundary_id - 1].push_back((j + 2) % 3);
352 
353  //If using regions set up the boundary information
354  if (use_attributes)
355  {
356  unsigned tmp_region =
357  static_cast<unsigned> (Tmp_mesh_pt->element_attribute(e));
358  //Element adjacent to boundary
359  Boundary_region_element_pt[boundary_id - 1]
360  [tmp_region].push_back(elem_pt);
361  //Need to put a shift in here because of an inconsistent naming
362  //convention between triangle and face elements
363  Face_index_region_at_boundary[boundary_id - 1]
364  [tmp_region].push_back((j + 2) % 3);
365  }
366  }
367 
368  } //end of loop over edges
369  } //end of loop over elements
370 
371 
372  // Lookup scheme has now been setup
373  Lookup_for_elements_next_boundary_is_setup = true;
374 
375  }
376 
377 #ifdef OOMPH_HAS_MPI
378 
379  //======================================================================
380  /// \short Identify the segments from the old mesh (original mesh)
381  /// in the new mesh (this) and assign initial and final boundary
382  /// coordinates for the segments that create the boundary
383  //======================================================================
384  template<class ELEMENT>
387  const unsigned& b, TriangleMesh<ELEMENT>* original_mesh_pt)
388  {
389  // ------------------------------------------------------------------
390  // First: Get the face elements associated with the current boundary
391  // (nonhalo elements only)
392  // ------------------------------------------------------------------
393  // Temporary storage for face elements
394  Vector<FiniteElement*> face_el_pt;
395 
396  // Temporary storage for number of elements adjacent to the boundary
397  unsigned nele = 0;
398 
399  // Temporary storage for elements adjacent to the boundary that have
400  // a common edge (related with internal boundaries)
401  unsigned n_repeated_ele = 0;
402 
403  const unsigned n_regions = this->nregion();
404 
405  // map to associate the face element to the bulk element, necessary
406  // to attach halo face elements at both sides of each found segment
407  std::map<FiniteElement*,FiniteElement*> face_to_bulk_element_pt;
408 
409  // Temporary storage for already done nodes
410  Vector<std::pair<Node*, Node*> > done_nodes_pt;
411 
412  // If there is more than one region then only use boundary
413  // coordinates from the bulk side (region 0)
414  if (n_regions > 1)
415  {
416  for (unsigned rr = 0 ; rr < n_regions; rr++)
417  {
418  const unsigned region_id =
419  static_cast<unsigned>(this->Region_attribute[rr]);
420 
421  // Loop over all elements on boundaries in region i_r
422  const unsigned nel_in_region =
423  this->nboundary_element_in_region(b, region_id);
424 
425  unsigned nel_repetead_in_region = 0;
426 
427  // Only bother to do anything else, if there are elements
428  // associated with the boundary and the current region
429  if (nel_in_region > 0)
430  {
431  // Flag that activates when a repeated face element is found,
432  // possibly because we are dealing with an internal boundary
433  bool repeated = false;
434 
435  // Loop over the bulk elements adjacent to boundary b
436  for (unsigned e = 0; e < nel_in_region; e++)
437  {
438  // Get pointer to the bulk element that is adjacent to boundary b
439  FiniteElement* bulk_elem_pt =
440  this->boundary_element_in_region_pt(b, region_id, e);
441 
442 #ifdef OOMPH_HAS_MPI
443  // In a distributed mesh only work with nonhalo elements
444  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
445  {
446  // Increase the number of repeated elements
447  n_repeated_ele++;
448  // Go for the next element
449  continue;
450  }
451 #endif
452 
453  //Find the index of the face of element e along boundary b
454  int face_index =
455  this->face_index_at_boundary_in_region(b,region_id,e);
456 
457  // Before adding the new element we need to be sure that
458  // the edge that this element represent has not been
459  // already added
460  FiniteElement* tmp_ele_pt =
461  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
462 
463  const unsigned n_nodes = tmp_ele_pt->nnode();
464 
465  std::pair<Node*, Node*> tmp_pair =
466  std::make_pair(tmp_ele_pt->node_pt(0),
467  tmp_ele_pt->node_pt(n_nodes - 1));
468 
469  std::pair<Node*, Node*> tmp_pair_inverse =
470  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
471  tmp_ele_pt->node_pt(0));
472 
473  // Search for repeated nodes
474  const unsigned n_done_nodes = done_nodes_pt.size();
475  for (unsigned l = 0; l < n_done_nodes; l++)
476  {
477  if (tmp_pair == done_nodes_pt[l] ||
478  tmp_pair_inverse == done_nodes_pt[l])
479  {
480  nel_repetead_in_region++;
481  repeated = true;
482  break;
483  }
484  }
485 
486  // Create new face element
487  if (!repeated)
488  {
489  // Add the pair of nodes (edge) to the node dones
490  done_nodes_pt.push_back(tmp_pair);
491  // Create the map to know if the element is halo
492  face_el_pt.push_back(tmp_ele_pt);
493  // Add the element to the face elements
494  face_to_bulk_element_pt[tmp_ele_pt] = bulk_elem_pt;
495  }
496  else
497  {
498  // Clean up
499  delete tmp_ele_pt;
500  tmp_ele_pt = 0;
501  }
502 
503  // Re-start
504  repeated = false;
505 
506  } // for (e < nel_in_region)
507 
508  nele += nel_in_region;
509 
510  n_repeated_ele += nel_repetead_in_region;
511 
512  } // if (nel_in_region > 0)
513  } // for (rr < n_regions)
514  } // if (n_regions > 1)
515  //Otherwise it's just the normal boundary functions
516  else
517  {
518  // Loop over all elements on boundaries
519  nele = this->nboundary_element(b);
520 
521  //Only bother to do anything else, if there are elements
522  if (nele > 0)
523  {
524  // Flag that activates when a repeated face element is found,
525  // possibly because we are dealing with an internal boundary
526  bool repeated = false;
527 
528  // Loop over the bulk elements adjacent to boundary b
529  for (unsigned e = 0; e < nele; e++)
530  {
531  // Get pointer to the bulk element that is adjacent to boundary b
532  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
533 
534 #ifdef OOMPH_HAS_MPI
535  // In a distributed mesh only work with nonhalo elements
536  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
537  {
538  // Increase the number of repeated elements
539  n_repeated_ele++;
540  // Go for the next element
541  continue;
542  }
543 #endif
544 
545  //Find the index of the face of element e along boundary b
546  int face_index = this->face_index_at_boundary(b, e);
547 
548  // Before adding the new element we need to be sure that
549  // the edge that this element represents has not been
550  // already added (only applies for internal boundaries)
551  FiniteElement* tmp_ele_pt =
552  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
553 
554  const unsigned n_nodes = tmp_ele_pt->nnode();
555 
556  std::pair<Node*, Node*> tmp_pair =
557  std::make_pair(tmp_ele_pt->node_pt(0),
558  tmp_ele_pt->node_pt(n_nodes - 1));
559 
560  std::pair<Node*, Node*> tmp_pair_inverse =
561  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
562  tmp_ele_pt->node_pt(0));
563 
564  // Search for repeated nodes
565  const unsigned n_done_nodes = done_nodes_pt.size();
566  for (unsigned l = 0; l < n_done_nodes; l++)
567  {
568  if (tmp_pair == done_nodes_pt[l] ||
569  tmp_pair_inverse == done_nodes_pt[l])
570  {
571  // Increase the number of repeated elements
572  n_repeated_ele++;
573  // Mark the element as repeated
574  repeated = true;
575  break;
576  }
577  }
578 
579  // Create new face element
580  if (!repeated)
581  {
582  // Add the pair of nodes (edge) to the node dones
583  done_nodes_pt.push_back(tmp_pair);
584  // Add the element to the face elements
585  face_el_pt.push_back(tmp_ele_pt);
586  // Create the map to know if the element is halo
587  face_to_bulk_element_pt[tmp_ele_pt] = bulk_elem_pt;
588  }
589  else
590  {
591  // Free the repeated bulk element!!
592  delete tmp_ele_pt;
593  tmp_ele_pt = 0;
594  }
595 
596  // Re-start
597  repeated = false;
598 
599  } // for (e < nel)
600  } // if (nel > 0)
601 
602  } // else (n_regions > 1)
603 
604  // Do not consider the repeated elements
605  nele-= n_repeated_ele;
606 
607 #ifdef PARANOID
608  if (nele!=face_el_pt.size())
609  {
610  std::ostringstream error_message;
611  error_message
612  << "The independent counting of face elements ("<<nele<<") for "
613  << "boundary ("<<b<<") is different\n"
614  << "from the real number of face elements in the container ("
615  << face_el_pt.size() <<")\n";
616  throw OomphLibError(error_message.str(),
617  "TriangleMesh::identify_boundary_segments_and_assign_initial_zeta_values()",
618  OOMPH_EXCEPTION_LOCATION);
619  }
620 #endif
621 
622  // Continue even thought there are no elements, the processor needs
623  // to participate in the communications
624 
625  // ----------------------------------------------------------------
626  // Second: Sort the face elements, only consider nonhalo elements
627  // ----------------------------------------------------------------
628 
629  // A flag vector to mark those face elements that are considered as
630  // halo in the current processor
631  std::vector<bool> is_halo_face_element(nele,false);
632 
633  // Count the total number of non halo face elements
634  unsigned nnon_halo_face_elements = 0;
635 
636  // We will have halo face elements if the mesh is distributed
637  for (unsigned ie = 0; ie < nele; ie++)
638  {
639  // Get the face element
640  FiniteElement* face_ele_pt = face_el_pt[ie];
641  // Get the bulk element
642  FiniteElement* tmp_bulk_ele_pt = face_to_bulk_element_pt[face_ele_pt];
643  // Check if the bulk element is halo
644  if (!tmp_bulk_ele_pt->is_halo())
645  {
646  is_halo_face_element[ie] = false;
647  nnon_halo_face_elements++;
648  }
649  else
650  {
651  // Mark the face element as halo
652  is_halo_face_element[ie] = true;
653  }
654  } // for (ie < nele)
655 
656 #ifdef PARANOID
657  // Get the total number of halo face elements
658  const unsigned nhalo_face_element = nele - nnon_halo_face_elements;
659  if (nhalo_face_element > 0)
660  {
661  std::ostringstream error_message;
662  error_message
663  << "There should not be halo face elements since they were not "
664  << "considered when computing the face elements\n\n"
665  << "The number of found halo face elements is: "
666  << nhalo_face_element << "\n\n";
667  throw OomphLibError(error_message.str(),
668  "TriangleMesh::identify_boundary_segments_and_assign_initial_zeta_values()",
669  OOMPH_EXCEPTION_LOCATION);
670  }
671 #endif
672 
673  // The vector of list to store the "segments" that compound the
674  // boundary (segments may appear only in a distributed mesh)
675  Vector<std::list<FiniteElement*> > segment_sorted_ele_pt;
676 
677  // Number of already sorted face elements (only nonhalo elements for
678  // a distributed mesh)
679  unsigned nsorted_face_elements = 0;
680 
681  // Keep track of who's done (this apply to nonhalo only, remember we
682  // are only working with nonhalo elements)
683  std::map<FiniteElement*, bool> done_el;
684 
685  // Keep track of which element is inverted (in distributed mesh the
686  // elements may be inverted with respect to the segment they belong)
687  std::map<FiniteElement*, bool> is_inverted;
688 
689  // Iterate until all possible segments have been created
690  while(nsorted_face_elements < nnon_halo_face_elements)
691  {
692  // The ordered list of face elements (in a distributed mesh a
693  // collection of contiguous face elements define a segment)
694  std::list<FiniteElement*> sorted_el_pt;
695  sorted_el_pt.clear();
696 
697 #ifdef PARANOID
698  // Select an initial element for the segment
699  bool found_initial_face_element = false;
700 #endif
701 
702  FiniteElement* ele_face_pt = 0;
703 
704  unsigned iface = 0;
705  for (iface = 0; iface < nele; iface++)
706  {
707  if (!is_halo_face_element[iface])
708  {
709  ele_face_pt = face_el_pt[iface];
710  // If not done then take it as initial face element
711  if (!done_el[ele_face_pt])
712  {
713 #ifdef PARANOID
714  found_initial_face_element = true;
715 #endif
716  nsorted_face_elements++;
717  iface++; // The next element number
718  sorted_el_pt.push_back(ele_face_pt);
719  // Mark as done
720  done_el[ele_face_pt] = true;
721  break;
722  }
723  }
724  } // for (iface < nele)
725 
726 #ifdef PARANOID
727  if (!found_initial_face_element)
728  {
729  std::ostringstream error_message;
730  error_message
731  <<"Could not find an initial face element for the current segment\n";
732  throw OomphLibError(error_message.str(),
733  "TriangleMesh::identify_boundary_segments_and_assign_initial_zeta_values()",
734  OOMPH_EXCEPTION_LOCATION);
735  }
736 #endif
737 
738  // Number of nodes
739  const unsigned nnod = ele_face_pt->nnode();
740 
741  // Left and right most nodes (the left and right nodes of the
742  // current face element)
743  Node* left_node_pt = ele_face_pt->node_pt(0);
744  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
745 
746  // Continue iterating if a new face element has been added to the
747  // list
748  bool face_element_added = false;
749 
750  // While a new face element has been added to the set of sorted
751  // face elements then re-iterate
752  do
753  {
754  // Start from the next face element since we have already added
755  // the previous one as the initial face element (any previous
756  // face element had to be added on previous iterations)
757  for (unsigned iiface = iface; iiface < nele; iiface++)
758  {
759  // Re-start flag
760  face_element_added = false;
761 
762  // Get the candidate element
763  ele_face_pt = face_el_pt[iiface];
764 
765  // Check that the candidate element has not been done and is
766  // not a halo element
767  if (!(done_el[ele_face_pt] || is_halo_face_element[iiface]))
768  {
769  // Get the left and right nodes of the current element
770  Node* local_left_node_pt = ele_face_pt->node_pt(0);
771  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
772  // New element fits at the left of segment and is not inverted
773  if (left_node_pt == local_right_node_pt)
774  {
775  left_node_pt = local_left_node_pt;
776  sorted_el_pt.push_front(ele_face_pt);
777  is_inverted[ele_face_pt] = false;
778  face_element_added = true;
779  }
780  // New element fits at the left of segment and is inverted
781  else if (left_node_pt == local_left_node_pt)
782  {
783  left_node_pt = local_right_node_pt;
784  sorted_el_pt.push_front(ele_face_pt);
785  is_inverted[ele_face_pt] = true;
786  face_element_added = true;
787  }
788  // New element fits on the right of segment and is not inverted
789  else if (right_node_pt == local_left_node_pt)
790  {
791  right_node_pt = local_right_node_pt;
792  sorted_el_pt.push_back(ele_face_pt);
793  is_inverted[ele_face_pt] = false;
794  face_element_added = true;
795  }
796  // New element fits on the right of segment and is inverted
797  else if (right_node_pt == local_right_node_pt)
798  {
799  right_node_pt = local_left_node_pt;
800  sorted_el_pt.push_back(ele_face_pt);
801  is_inverted[ele_face_pt] = true;
802  face_element_added = true;
803  }
804 
805  if (face_element_added)
806  {
807  done_el[ele_face_pt] = true;
808  nsorted_face_elements++;
809  break;
810  }
811 
812  } // if (!(done_el[ele_face_pt] || is_halo_face_element[iiface]))
813  } // for (iiface<nnon_halo_face_element)
814  }while(face_element_added &&
815  (nsorted_face_elements < nnon_halo_face_elements));
816 
817  // Store the created segment in the vector of segments
818  segment_sorted_ele_pt.push_back(sorted_el_pt);
819 
820  } // while(nsorted_face_elements < nnon_halo_face_elements);
821 
822  // The number of segments in this processor
823  const unsigned nsegments = segment_sorted_ele_pt.size();
824 
825  // ------------------------------------------------------------------
826  // Third: We have the face elements sorted (nonhalo only), now
827  // assign boundary coordinates to the nodes in the segments. This is
828  // the LOCAL boundary coordinate which is required if the zeta
829  // values need to be inverted
830  // ------------------------------------------------------------------
831  // Necessary in case boundaries with no geom object associated need
832  // to be inverted the zeta values (It is necessary to compute the
833  // arclength but also to store the nodes in a container (set))
834  // ------------------------------------------------------------------
835 
836  // Vector of sets that stores the nodes of each segment based on a
837  // lexicographically order starting from the bottom left node of
838  // each segment
839  Vector<std::set<Node*> > segment_all_nodes_pt;
840 
841  // The arclength of each segment in the current processor
842  Vector<double> segment_arclength(nsegments);
843 
844  // The number of vertices of each segment
845  Vector<unsigned> nvertices_per_segment(nsegments);
846 
847  // The initial zeta for the segment
848  Vector<double> initial_zeta_segment(nsegments);
849 
850  // The final zeta for the segment
851  Vector<double> final_zeta_segment(nsegments);
852 
853 #ifdef PARANOID
854  if (nnon_halo_face_elements > 0 && nsegments == 0)
855  {
856  std::ostringstream error_message;
857  error_message
858  << "The number of segments is zero, but the number of nonhalo\n"
859  << "elements is: (" << nnon_halo_face_elements << ")\n";
860  throw OomphLibError(error_message.str(),
861  "TriangleMesh::identify_boundary_segments_and_assign_initial_zeta_values()",
862  OOMPH_EXCEPTION_LOCATION);
863  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
864 #endif
865 
866  // Go through all the segments and compute the LOCAL boundary
867  // coordinates
868  for (unsigned is = 0; is < nsegments; is++)
869  {
870 #ifdef PARANOID
871  if (segment_sorted_ele_pt[is].size() == 0)
872  {
873  std::ostringstream error_message;
874  error_message
875  << "The (" << is << ")-th segment has no elements\n";
876  throw OomphLibError(error_message.str(),
877  "TriangleMesh::identify_boundary_segments_and_assign_initial_zeta_values()",
878  OOMPH_EXCEPTION_LOCATION);
879  } // if (segment_sorted_ele_pt[is].size() == 0)
880 #endif
881 
882  // Get access to the first element on the segment
883  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
884 
885  // Number of nodes
886  const unsigned nnod = first_ele_pt->nnode();
887 
888  // Get the first node of the current segment
889  Node *first_node_pt = first_ele_pt->node_pt(0);
890  if (is_inverted[first_ele_pt])
891  {
892  first_node_pt = first_ele_pt->node_pt(nnod-1);
893  }
894 
895  // Get access to the last element on the segment
896  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
897 
898  // Get the last node of the current segment
899  Node *last_node_pt = last_ele_pt->node_pt(nnod-1);
900  if (is_inverted[last_ele_pt])
901  {
902  last_node_pt = last_ele_pt->node_pt(0);
903  }
904 
905  // Coordinates of left node
906  double x_left = first_node_pt->x(0);
907  double y_left = first_node_pt->x(1);
908 
909  // Initialise boundary coordinate (local boundary coordinate for
910  // boundaries with more than one segment)
911  Vector<double> zeta(1, 0.0);
912 
913  // If the boundary has an associated GeomObject then it is not
914  // necessary to compute the arclength, only read the values from
915  // the nodes at the edges
916  if (this->boundary_geom_object_pt(b)!=0)
917  {
918  first_node_pt->get_coordinates_on_boundary(b, zeta);
919  initial_zeta_segment[is] = zeta[0];
920  last_node_pt->get_coordinates_on_boundary(b, zeta);
921  final_zeta_segment[is] = zeta[0];
922  }
923 
924  // Lexicographically bottom left node
925  std::set<Node*> local_nodes_pt;
926  local_nodes_pt.insert(first_node_pt);
927 
928  // Now loop over nodes in order
929  for (std::list<FiniteElement*>::iterator it =
930  segment_sorted_ele_pt[is].begin();
931  it != segment_sorted_ele_pt[is].end(); it++)
932  {
933  // Get element
934  FiniteElement* el_pt = *it;
935 
936  // Start node and increment
937  unsigned k_nod = 1;
938  int nod_diff = 1;
939  if (is_inverted[el_pt])
940  {
941  k_nod = nnod - 2;
942  nod_diff = -1;
943  }
944 
945  // Loop over nodes
946  for (unsigned j = 1; j < nnod; j++)
947  {
948  Node* nod_pt = el_pt->node_pt(k_nod);
949  k_nod += nod_diff;
950 
951  // Coordinates of right node
952  double x_right = nod_pt->x(0);
953  double y_right = nod_pt->x(1);
954 
955  // Increment boundary coordinate (the arclength)
956  zeta[0] += sqrt(
957  (x_right - x_left) * (x_right - x_left) + (y_right - y_left)
958  * (y_right - y_left));
959 
960  // // When we have a GeomObject associated to the boundary we already
961  // // know the zeta values for the nodes, there is no need to compute
962  // // the arclength
963  // if (this->boundary_geom_object_pt(b)==0)
964  // {
965  // // Set boundary coordinate
966  // nod_pt->set_coordinates_on_boundary(b, zeta);
967  // }
968 
969  // Increment reference coordinate
970  x_left = x_right;
971  y_left = y_right;
972 
973  // Get lexicographically bottom left node but only
974  // use vertex nodes as candidates
975  local_nodes_pt.insert(nod_pt);
976  } // for (j < nnod)
977 
978  } // iterator over the elements in the segment
979 
980  // Store the arclength of the segment
981  segment_arclength[is] = zeta[0];
982 
983  // Store the number of vertices in the segment
984  nvertices_per_segment[is] = local_nodes_pt.size();
985 
986  // Add the nodes for the corresponding segment in the container
987  segment_all_nodes_pt.push_back(local_nodes_pt);
988 
989  } // for (is < nsegments)
990 
991  // Get the number of sets for nodes
992 #ifdef PARANOID
993  if (segment_all_nodes_pt.size() != nsegments)
994  {
995  std::ostringstream error_message;
996  error_message
997  <<"The number of segments ("<<nsegments<<") and the number of "
998  <<"sets of nodes ("<<segment_all_nodes_pt.size()<<") representing\n"
999  <<"the\nsegments is different!!!\n\n";
1000  throw OomphLibError(
1001  error_message.str(),
1002  OOMPH_CURRENT_FUNCTION,
1003  OOMPH_EXCEPTION_LOCATION);
1004  }
1005 #endif
1006 
1007  // Store the initial arclength for each segment of boundary in the
1008  // current processor, initalise to zero in case we have a non
1009  // distributed boundary
1010  Vector<double> initial_segment_arclength(nsegments,0.0);
1011 
1012  // Associated the index of the current segment to the segment index
1013  // in the original mesh (input mesh)
1014  Vector<unsigned> current_segment_to_original_segment_index(nsegments);
1015 
1016  // Each segment needs to know whether it has to be inverted or not
1017  // Store whether a segment needs to be inverted or not
1018  Vector<unsigned> segment_inverted(nsegments);
1019 
1020  // -----------------------------------------------------------------
1021  // Fourth: Identify the segments with the ones in the original mesh
1022  // (has sense only in the adaptation process)
1023  // -----------------------------------------------------------------
1024 
1025  // Now check if there are segments associated to this boundary
1026  if (nsegments > 0)
1027  {
1028 #ifdef PARANOID
1029  // Double check that the same number of coordinates (nsegments)
1030  // have been established for the boundary
1031  const unsigned nsegments_initial_coordinates =
1032  original_mesh_pt->boundary_segment_initial_coordinate(b).size();
1033 
1034  const unsigned nsegments_final_coordinates =
1035  original_mesh_pt->boundary_segment_final_coordinate(b).size();
1036 
1037  if (nsegments_initial_coordinates!=nsegments_final_coordinates)
1038  {
1039  std::stringstream error_message;
1040  error_message
1041  <<"The number of segments that present initial coordinates "
1042  <<nsegments_initial_coordinates<<" is different from "
1043  <<"the\nnumber of segments that present final coordinates "
1044  <<nsegments_final_coordinates<<"\n\n";
1045  throw OomphLibError(
1046  error_message.str(),
1047  OOMPH_CURRENT_FUNCTION,
1048  OOMPH_EXCEPTION_LOCATION);
1049  } // if (nsegments_initial_coordinates!=nsegments_final_coordinates)
1050 
1051  // Also check that the number of segments found in the previous
1052  // mesh is the same as the number of segments found in this mesh
1053  if (nsegments_initial_coordinates != nsegments)
1054  {
1055  std::stringstream error_message;
1056  error_message
1057  <<"Working with boundary ("<< b << ").\n The number of initial and "
1058  <<"final coordinates ("
1059  <<nsegments_initial_coordinates<<") is different from\n"
1060  <<"the number of found segments ("<< nsegments <<").\n\n";
1061  throw OomphLibError(
1062  error_message.str(),
1063  OOMPH_CURRENT_FUNCTION,
1064  OOMPH_EXCEPTION_LOCATION);
1065  } // if (nsegments_initial_coordinates != nsegments)
1066 #endif
1067 
1068  // Create a backup for the data from the original mesh
1069  // Backup for the coordinates
1070  Vector<Vector<double> >original_mesh_segment_initial_coordinate(nsegments);
1071  Vector<Vector<double> >original_mesh_segment_final_coordinate(nsegments);
1072  // Backup for the zeta values
1073  Vector<double> original_mesh_segment_initial_zeta(nsegments);
1074  Vector<double> original_mesh_segment_final_zeta(nsegments);
1075  // Backup for the arclengths
1076  Vector<double> original_mesh_segment_initial_arclength(nsegments);
1077  Vector<double> original_mesh_segment_final_arclength(nsegments);
1078  // Do the backup
1079  for (unsigned is = 0; is < nsegments; is++)
1080  {
1081  original_mesh_segment_initial_coordinate[is].resize(2);
1082  original_mesh_segment_final_coordinate[is].resize(2);
1083  for (unsigned k = 0; k < 2; k++)
1084  {
1085  original_mesh_segment_initial_coordinate[is][k] =
1086  original_mesh_pt->boundary_segment_initial_coordinate(b)[is][k];
1087  original_mesh_segment_final_coordinate[is][k] =
1088  original_mesh_pt->boundary_segment_final_coordinate(b)[is][k];
1089  }
1090  // Check if the boudary has an associated GeomObject
1091  if (this->boundary_geom_object_pt(b)!=0)
1092  {
1093  original_mesh_segment_initial_zeta[is] =
1094  original_mesh_pt->boundary_segment_initial_zeta(b)[is];
1095  original_mesh_segment_final_zeta[is] =
1096  original_mesh_pt->boundary_segment_final_zeta(b)[is];
1097  }
1098  else
1099  {
1100  original_mesh_segment_initial_arclength[is] =
1101  original_mesh_pt->boundary_segment_initial_arclength(b)[is];
1102  original_mesh_segment_final_arclength[is] =
1103  original_mesh_pt->boundary_segment_final_arclength(b)[is];
1104  }
1105  } // for (is < nsegments)
1106 
1107  // Clear all the storage
1108  Boundary_segment_inverted[b].clear();
1109  Boundary_segment_initial_coordinate[b].clear();
1110  Boundary_segment_final_coordinate[b].clear();
1111 
1112  Boundary_segment_initial_zeta[b].clear();
1113  Boundary_segment_final_zeta[b].clear();
1114 
1115  Boundary_segment_initial_arclength[b].clear();
1116  Boundary_segment_final_arclength[b].clear();
1117 
1118  // Identify each segment in the processor with the ones created
1119  // by the original mesh
1120  // -----------------------------------------------------------------
1121  // Keep track of the already identified segments
1122  std::map<unsigned,bool> segment_done;
1123  for (unsigned is = 0; is < nsegments; is++)
1124  {
1125 #ifdef PARANOID
1126  // Flag to know if the segment was identified
1127  bool found_original_segment = false;
1128 #endif
1129 
1130  // Get the initial and final coordinates of the current segment
1131  Vector<double> current_seg_initial_coord(2);
1132  Vector<double> current_seg_final_coord(2);
1133 
1134  // Get access to the initial element on the segment
1135  FiniteElement* current_seg_initial_ele_pt =
1136  segment_sorted_ele_pt[is].front();
1137 
1138  // Number of nodes
1139  const unsigned nnod = current_seg_initial_ele_pt->nnode();
1140 
1141  // Get the first node of the current segment
1142  Node *current_seg_first_node_pt=
1143  current_seg_initial_ele_pt->node_pt(0);
1144  if (is_inverted[current_seg_initial_ele_pt])
1145  {
1146  current_seg_first_node_pt =
1147  current_seg_initial_ele_pt->node_pt(nnod-1);
1148  }
1149 
1150  // Get access to the last element on the segment
1151  FiniteElement* current_seg_last_ele_pt =
1152  segment_sorted_ele_pt[is].back();
1153 
1154  // Get the last node of the current segment
1155  Node *current_seg_last_node_pt =
1156  current_seg_last_ele_pt->node_pt(nnod-1);
1157  if (is_inverted[current_seg_last_ele_pt])
1158  {
1159  current_seg_last_node_pt =
1160  current_seg_last_ele_pt->node_pt(0);
1161  }
1162 
1163  // Get the coordinates for the first and last seg node
1164  for (unsigned i = 0; i < 2; i++)
1165  {
1166  current_seg_initial_coord[i]=current_seg_first_node_pt->x(i);
1167  current_seg_final_coord[i]=current_seg_last_node_pt->x(i);
1168  }
1169 
1170  // We have got the initial and final coordinates of the current
1171  // segment, compare those with the initial and final coordinates
1172  // of the original mesh segments to identify which segments is
1173  // which
1174  for (unsigned orig_s = 0; orig_s < nsegments; orig_s++)
1175  {
1176  if (!segment_done[orig_s])
1177  {
1178  // Get the coordinates to compare
1179  Vector<double> initial_coordinate =
1180  original_mesh_segment_initial_coordinate[orig_s];
1181  Vector<double> final_coordinate =
1182  original_mesh_segment_final_coordinate[orig_s];
1183 
1184  // Compute the distance initial(current)-initial(original)
1185  // coordinates
1186  double dist =
1187  ((current_seg_initial_coord[0] - initial_coordinate[0])*
1188  (current_seg_initial_coord[0] - initial_coordinate[0]))
1189  +
1190  ((current_seg_initial_coord[1] - initial_coordinate[1])*
1191  (current_seg_initial_coord[1] - initial_coordinate[1]));
1192  dist = sqrt(dist);
1193 
1194  // If the initial node is the same, check for the last node
1195  if (dist <
1196  ToleranceForVertexMismatchInPolygons::Tolerable_error)
1197  {
1198  // Compute the distance final(current)-final(original)
1199  // coordinates
1200  dist =
1201  ((current_seg_final_coord[0] - final_coordinate[0])*
1202  (current_seg_final_coord[0] - final_coordinate[0]))
1203  +
1204  ((current_seg_final_coord[1] - final_coordinate[1])*
1205  (current_seg_final_coord[1] - final_coordinate[1]));
1206  dist = sqrt(dist);
1207 
1208  // The final node is the same, we have identified the
1209  // segments
1210  if (dist <
1211  ToleranceForVertexMismatchInPolygons::Tolerable_error)
1212  {
1213  // Store the index that relates the previous index with the
1214  // current one
1215  current_segment_to_original_segment_index[is] = orig_s;
1216 
1217  // In this case the segment is not inverted
1218  Boundary_segment_inverted[b].push_back(0);
1219 
1220  // Copy the initial and final coordinates for each segment
1221  Boundary_segment_initial_coordinate[b].push_back(
1222  initial_coordinate);
1223  Boundary_segment_final_coordinate[b].push_back(
1224  final_coordinate);
1225 
1226  // Check if the boundary has an associated GeomObject
1227  if (this->boundary_geom_object_pt(b)!=0)
1228  {
1229  // Copy the initial zeta value for the segment
1230  Boundary_segment_initial_zeta[b].push_back(
1231  original_mesh_segment_initial_zeta[orig_s]);
1232  Boundary_segment_final_zeta[b].push_back(
1233  original_mesh_segment_final_zeta[orig_s]);
1234  }
1235  else
1236  {
1237  // Copy the initial and final arclength for each
1238  // segment
1239  Boundary_segment_initial_arclength[b].push_back(
1240  original_mesh_segment_initial_arclength[orig_s]);
1241  Boundary_segment_final_arclength[b].push_back(
1242  original_mesh_segment_final_arclength[orig_s]);
1243  }
1244  // Mark the segment as done
1245  segment_done[orig_s] = true;
1246 #ifdef PARANOID
1247  found_original_segment = true;
1248 #endif
1249  break;
1250  } // The final(current) node matched with the
1251  // final(original) node
1252  } // The initial(current) node matched with the
1253  // initial(original) node
1254  else
1255  {
1256  // Check the inverted case Compute the distance
1257  // initial(current)-final(original) coordinates
1258  double dist_inv =
1259  ((current_seg_initial_coord[0] - final_coordinate[0])*
1260  (current_seg_initial_coord[0] - final_coordinate[0]))
1261  +
1262  ((current_seg_initial_coord[1] - final_coordinate[1])*
1263  (current_seg_initial_coord[1] - final_coordinate[1]));
1264  dist_inv = sqrt(dist_inv);
1265 
1266  // If the initial node is the same as the final node of
1267  // the segment, check for the last node
1268  if (dist_inv <
1269  ToleranceForVertexMismatchInPolygons::Tolerable_error)
1270  {
1271  // Compute the distance final(current)-initial(original)
1272  // coordinates
1273  dist_inv =
1274  ((current_seg_final_coord[0] - initial_coordinate[0])*
1275  (current_seg_final_coord[0] - initial_coordinate[0]))
1276  +
1277  ((current_seg_final_coord[1] - initial_coordinate[1])*
1278  (current_seg_final_coord[1] - initial_coordinate[1]));
1279  dist_inv = sqrt(dist_inv);
1280 
1281  // The final node is the same as the initial node, we
1282  // have identified the segments
1283  if (dist_inv <
1284  ToleranceForVertexMismatchInPolygons::Tolerable_error)
1285  {
1286  // Store the index that related the previous index with the
1287  // current one
1288  current_segment_to_original_segment_index[is] = orig_s;
1289 
1290  // In this case the segment is inverted
1291  Boundary_segment_inverted[b].push_back(1);
1292 
1293  // Copy the initial and final coordinates for each segment
1294  Boundary_segment_initial_coordinate[b].push_back(
1295  initial_coordinate);
1296  Boundary_segment_final_coordinate[b].push_back(
1297  final_coordinate);
1298 
1299  // Check that the boudary has an associated GeomObject
1300  if (this->boundary_geom_object_pt(b)!=0)
1301  {
1302  // Copy the initial zeta value for the segments
1303  Boundary_segment_initial_zeta[b].push_back(
1304  original_mesh_segment_initial_zeta[orig_s]);
1305  Boundary_segment_final_zeta[b].push_back(
1306  original_mesh_segment_final_zeta[orig_s]);
1307  }
1308  else
1309  {
1310  // Copy the initial and final arclength for each segment
1311  Boundary_segment_initial_arclength[b].push_back(
1312  original_mesh_segment_initial_arclength[orig_s]);
1313  Boundary_segment_final_arclength[b].push_back(
1314  original_mesh_segment_final_arclength[orig_s]);
1315  }
1316  // Mark the segment as done
1317  segment_done[orig_s] = true;
1318 #ifdef PARANOID
1319  found_original_segment = true;
1320 #endif
1321  break;
1322  } // The final(current) node matched with the
1323  // initial(original) node
1324  } // The initial(current) node matched with the
1325  // final(original) node
1326  } // else (the first(current) node did not matched with the
1327  // first(original) node. Else do the inverted case
1328 
1329  } // (!segment_done[orig_s])
1330 
1331  } // (orig_s < nsegments)
1332 
1333 #ifdef PARANOID
1334  if (!found_original_segment)
1335  {
1336  std::stringstream error_message;
1337  error_message
1338  <<"The ("<<is<<")-th segment on the current segment was not\n"
1339  << "found when trying to identify it with the original mesh's\n"
1340  << "segment coordinates\n";
1341  throw OomphLibError(error_message.str(),
1342  OOMPH_CURRENT_FUNCTION,
1343  OOMPH_EXCEPTION_LOCATION);
1344  } // if (!found_original_segment)
1345 #endif
1346  } // for (is < nsegments)
1347 
1348  } // if (nsegments > 0)
1349 
1350  // -------------------------------------------------------------------
1351  // Fourth: The original mesh is different from the current mesh
1352  // (this). For boundaries with no geom object associated check if it
1353  // is required to reverse the zeta values. In order to reverse the
1354  // zeta values it is required to previously compute the arclength of
1355  // the segments and store the nodes in a container (set). NOTE that
1356  // the setup_boundary_coordinate() method is not called for
1357  // boundaries with NO GeomObject associated, so this is the LAST
1358  // CHANCE to do it
1359  // -------------------------------------------------------------------
1360  // The original mesh is the same as the current mesh (this). The
1361  // setup_boundary_method() will be called only for the boundaries
1362  // with NO GeomObject associated
1363  // -------------------------------------------------------------------
1364  if (this != original_mesh_pt)
1365  {
1366  // Get the boundary arclength
1367 
1368  // Get the initial and final zeta values for the boundary
1369  // (arclength) from the original mesh
1370  Vector<double> first_node_zeta_coordinate =
1371  original_mesh_pt->boundary_initial_zeta_coordinate(b);
1372  Vector<double> last_node_zeta_coordinate =
1373  original_mesh_pt->boundary_final_zeta_coordinate(b);
1374 
1375  // The boundary arclength is the maximum of the initial and final
1376  // zeta coordinate
1377  const double boundary_arclength =
1378  std::max(first_node_zeta_coordinate[0],
1379  last_node_zeta_coordinate[0]);
1380 
1381  for (unsigned is = 0; is < nsegments; is++)
1382  {
1383  // Here check if need to invert the elements and the boundary
1384  // coordinates for the segments in a boundary with no GeomObject
1385  // associated
1386  if (boundary_geom_object_pt(b)==0)
1387  {
1388  // This case only applies for the initial and iterative mesh in
1389  // the adaptation process because the method
1390  // setup_boundary_coordinates() is called by the original mesh
1391  // for boundaries with no GeomObject associated
1392 
1393  // We are goind to check if it is necessary to invert the order
1394  // of the zeta values
1395 
1396  // Get the first and last node of the current segment and their
1397  // zeta values (arclength)
1398 
1399  // There is no need to check for nonhalo elements since the
1400  // container has only nonhalo face elements
1401 
1402  // Get access to the first element on the segment
1403  FiniteElement* first_ele_pt=segment_sorted_ele_pt[is].front();
1404 
1405  // Number of nodes
1406  const unsigned nnod = first_ele_pt->nnode();
1407 
1408  // Get the first node of the current segment
1409  Node *first_node_pt = first_ele_pt->node_pt(0);
1410  if (is_inverted[first_ele_pt])
1411  {
1412  first_node_pt = first_ele_pt->node_pt(nnod-1);
1413  }
1414 
1415  // Get access to the last element on the segment
1416  FiniteElement* last_ele_pt=segment_sorted_ele_pt[is].back();
1417 
1418  // Get the last node of the current segment
1419  Node *last_node_pt = last_ele_pt->node_pt(nnod-1);
1420  if (is_inverted[last_ele_pt])
1421  {
1422  last_node_pt = last_ele_pt->node_pt(0);
1423  }
1424 
1425  // Get the zeta coordinates for the first and last node
1426  Vector<double> current_segment_initial_arclen(1);
1427  Vector<double> current_segment_final_arclen(1);
1428  // Is the segment in the current mesh (this) inverted?
1429  if (!Boundary_segment_inverted[b][is]) // Not inverted
1430  {
1431  first_node_pt->
1432  get_coordinates_on_boundary(b, current_segment_initial_arclen);
1433  last_node_pt->
1434  get_coordinates_on_boundary(b, current_segment_final_arclen);
1435  }
1436  else // Inverted
1437  {
1438  first_node_pt->
1439  get_coordinates_on_boundary(b, current_segment_final_arclen);
1440  last_node_pt->
1441  get_coordinates_on_boundary(b, current_segment_initial_arclen);
1442  }
1443 
1444  // Once the zeta values have been obtained check if they are set
1445  // in increasing or decreasing order
1446 
1447  // Flag to state that the values in the segment are in increasing
1448  // order
1449  bool increasing_order = false;
1450 
1451  // If the initial zeta value is smaller than the final zeta
1452  // value then they are in increasing order
1453  if (current_segment_initial_arclen[0] <
1454  current_segment_final_arclen[0])
1455  {
1456  increasing_order = true;
1457  }
1458  // If the initial zeta value is greater than the initial zeta
1459  // value then they are in decreasing order
1460  else if (current_segment_initial_arclen[0] >
1461  current_segment_final_arclen[0])
1462  {
1463  increasing_order = false;
1464  }
1465 #ifdef PARANOID
1466  else
1467  {
1468  std::stringstream error_message;
1469  error_message
1470  << "It was not possible to identify if the zeta values on "
1471  << "boundary ("<<b<<")\nand segment ("<<is<<") should go in "
1472  << "increasing or decreasing order.\n--- New mesh ---\n"
1473  << "Current segment initial arclength: ("
1474  << current_segment_initial_arclen[0]<<")\n"
1475  << "First node coordinates: ("
1476  << first_node_pt->x(0) << ", " << first_node_pt->x(1) << ")\n"
1477  << "Current segment final arclength: ("
1478  << current_segment_final_arclen[0]<<")\n"
1479  << "Last node coordinates: ("
1480  << last_node_pt->x(0) << ", " << last_node_pt->x(1) << ")\n"
1481  << "Current segment arclength: ("
1482  << segment_arclength[is] <<")\n";
1483  throw OomphLibError(error_message.str(),
1484  OOMPH_CURRENT_FUNCTION,
1485  OOMPH_EXCEPTION_LOCATION);
1486  }
1487 #endif
1488 
1489  // Now get the original initial and final arclengths and check
1490  // if they are in increasing or decreasing order
1491  const unsigned prev_s =
1492  current_segment_to_original_segment_index[is];
1493  const double original_segment_initial_arclength =
1494  original_mesh_pt->boundary_segment_initial_arclength(b)[prev_s];
1495  const double original_segment_final_arclength =
1496  original_mesh_pt->boundary_segment_final_arclength(b)[prev_s];
1497 
1498  // Flag to check if the values go in increasing or decreasing
1499  // order in the original mesh segment
1500  bool original_increasing_order = false;
1501 
1502  // Now check if the arclengths on the original mesh go in
1503  // increase or decrease order, this is also used to choose the
1504  // starting value to map the values in the current segment
1505  double starting_arclength = 0.0;
1506  if (original_segment_final_arclength >
1507  original_segment_initial_arclength)
1508  {
1509  // ... in increasing order in the original mesh ...
1510  original_increasing_order = true;
1511  // Select the starting arclength
1512  starting_arclength = original_segment_initial_arclength;
1513  }
1514  else if (original_segment_final_arclength <
1515  original_segment_initial_arclength)
1516  {
1517  // ... in decreasing order in the original mesh ...
1518  original_increasing_order = false;
1519  // Select the starting arclength
1520  starting_arclength = original_segment_final_arclength;
1521  }
1522 #ifdef PARANOID
1523  else
1524  {
1525  std::stringstream error_message;
1526  error_message
1527  << "It was not possible to identify if the zeta values on "
1528  << "boundary ("<<b<<")\nand segment ("<<is<<") should go in "
1529  << "increasing or decreasing order.\n--- Original mesh ---\n"
1530  << "Original segment initial arclength: ("
1531  << original_segment_initial_arclength<<")\n"
1532  << "Original segment final arclength: ("
1533  << original_segment_final_arclength<<")\n";
1534  throw OomphLibError(error_message.str(),
1535  OOMPH_CURRENT_FUNCTION,
1536  OOMPH_EXCEPTION_LOCATION);
1537  }
1538 #endif
1539 
1540  // Now scale the zeta values based considering if the zeta
1541  // values from the current mesh (this) go in the same order as
1542  // in the original mesh
1543  if (increasing_order && original_increasing_order)
1544  {
1545  // Current seg
1546  // |------|
1547  // 0 ---- 1
1548  //
1549  // Is mapped to the new values
1550  // |------|
1551  // a ---- b
1552  // a = original_segment_initial_arclength
1553  // b = original_segment_final_arclength
1554  // s = starting_arclength
1555  // The mapping is given by
1556  // new_z = s + z_old * (b - a)
1557 
1558  // Get the nodes associated to the segment
1559  std::set<Node*> seg_nodes_pt = segment_all_nodes_pt[is];
1560  // Go through all the nodes in the segment an change their
1561  // zeta values
1562  for (std::set<Node*>::iterator it = seg_nodes_pt.begin();
1563  it != seg_nodes_pt.end(); it++)
1564  {
1565  // Storing for the zeta value
1566  Vector<double> zeta(1);
1567  // Get each node
1568  Node* nod_pt = (*it);
1569  // Get the zeta value of the current node
1570  nod_pt->get_coordinates_on_boundary(b, zeta);
1571  // ... and re-assign it
1572  const double temp =
1573  starting_arclength + (zeta[0] * segment_arclength[is]);
1574  // The zeta value
1575  zeta[0] = temp / boundary_arclength;
1576  // Correct
1577  if (std::fabs(zeta[0] - 1.0) < 1.0e-14)
1578  {
1579  zeta[0] = 1.0;
1580  }
1581  else if (std::fabs(zeta[0]) < 1.0e-14)
1582  {
1583  zeta[0] = 0.0;
1584  }
1585 
1586  // Set the new value
1587  nod_pt->set_coordinates_on_boundary(b, zeta);
1588  } // Go through all the nodes
1589  } // if (increasing_order && original_increasing_order)
1590  else if (!increasing_order && original_increasing_order)
1591  {
1592  // Current seg
1593  // |------|
1594  // 1 ---- 0
1595  //
1596  // Is mapped to the new values
1597  // |------|
1598  // a ---- b
1599  // a = original_segment_initial_arclength
1600  // b = original_segment_final_arclength
1601  // s = starting_arclength
1602  // The mapping is given by
1603  // new_z = s + (1.0 - z_old) * (b - a)
1604 
1605  // Get the nodes associated to the segment
1606  std::set<Node*> seg_nodes_pt = segment_all_nodes_pt[is];
1607  // Go through all the nodes in the segment an change their
1608  // zeta values
1609  for (std::set<Node*>::iterator it = seg_nodes_pt.begin();
1610  it != seg_nodes_pt.end(); it++)
1611  {
1612  // Storing for the zeta value
1613  Vector<double> zeta(1);
1614  // Get each node
1615  Node* nod_pt = (*it);
1616  // Get the zeta value of the current node
1617  nod_pt->get_coordinates_on_boundary(b, zeta);
1618  // ... and re-assign it
1619  const double temp =
1620  starting_arclength + ((1.0 - zeta[0]) * segment_arclength[is]);
1621  // The zeta value
1622  zeta[0] = temp / boundary_arclength;
1623  // Correct
1624  if (std::fabs(zeta[0] - 1.0) < 1.0e-14)
1625  {
1626  zeta[0] = 1.0;
1627  }
1628  else if (std::fabs(zeta[0]) < 1.0e-14)
1629  {
1630  zeta[0] = 0.0;
1631  }
1632  // Set the new value
1633  nod_pt->set_coordinates_on_boundary(b, zeta);
1634  } // Go through all the nodes
1635  } // else if (!increasing_order && original_increasing_order)
1636  else if (increasing_order && !original_increasing_order)
1637  {
1638  // Current seg
1639  // |------|
1640  // 0 ---- 1
1641  //
1642  // Is mapped to the new values
1643  // |------|
1644  // b ---- a
1645  // a = original_segment_initial_arclength
1646  // b = original_segment_final_arclength
1647  // s = starting_arclength
1648  // The mapping is given by
1649  // new_z = s + (1.0 - z_old) * |(b - a)|
1650 
1651  // Get the nodes associated to the segment
1652  std::set<Node*> seg_nodes_pt = segment_all_nodes_pt[is];
1653  // Go through all the nodes in the segment an change their
1654  // zeta values
1655  for (std::set<Node*>::iterator it = seg_nodes_pt.begin();
1656  it != seg_nodes_pt.end(); it++)
1657  {
1658  // Storing for the zeta value
1659  Vector<double> zeta(1);
1660  // Get each node
1661  Node* nod_pt = (*it);
1662  // Get the zeta value of the current node
1663  nod_pt->get_coordinates_on_boundary(b, zeta);
1664  // ... and re-assign it
1665  const double temp =
1666  starting_arclength + ((1.0 - zeta[0]) * segment_arclength[is]);
1667  // The zeta value
1668  zeta[0] = temp / boundary_arclength;
1669  // Correct
1670  if (std::fabs(zeta[0] - 1.0) < 1.0e-14)
1671  {
1672  zeta[0] = 1.0;
1673  }
1674  else if (std::fabs(zeta[0]) < 1.0e-14)
1675  {
1676  zeta[0] = 0.0;
1677  }
1678  // Set the new value
1679  nod_pt->set_coordinates_on_boundary(b, zeta);
1680  } // Go through all the nodes
1681  } // else if (increasing_order && !original_increasing_order)
1682  else if (!increasing_order && !original_increasing_order)
1683  {
1684  // Current seg
1685  // |------|
1686  // 0 ---- 1
1687  //
1688  // Is mapped to the new values
1689  // |------|
1690  // a ---- b
1691  // a = original_segment_initial_arclength
1692  // b = original_segment_final_arclength
1693  // s = starting_arclength
1694  // The mapping is given by
1695  // new_z = s + z_old * |(b - a)|
1696 
1697  // Get the nodes associated to the segment
1698  std::set<Node*> seg_nodes_pt = segment_all_nodes_pt[is];
1699  // Go through all the nodes in the segment an change their
1700  // zeta values
1701  for (std::set<Node*>::iterator it = seg_nodes_pt.begin();
1702  it != seg_nodes_pt.end(); it++)
1703  {
1704  // Storing for the zeta value
1705  Vector<double> zeta(1);
1706  // Get each node
1707  Node* nod_pt = (*it);
1708  // Get the zeta value of the current node
1709  nod_pt->get_coordinates_on_boundary(b, zeta);
1710  // ... and re-assign it
1711  const double temp =
1712  starting_arclength + (zeta[0] * segment_arclength[is]);
1713  // The zeta value
1714  zeta[0] = temp / boundary_arclength;
1715  // Correct
1716  if (std::fabs(zeta[0] - 1.0) < 1.0e-14)
1717  {
1718  zeta[0] = 1.0;
1719  }
1720  else if (std::fabs(zeta[0]) < 1.0e-14)
1721  {
1722  zeta[0] = 0.0;
1723  }
1724  // Set the new value
1725  nod_pt->set_coordinates_on_boundary(b, zeta);
1726  } // Go through all the nodes
1727  } // else if (!increasing_order && !original_increasing_order)
1728 
1729 #ifdef PARANOID
1730  // Verify that the z values of the first and last node are not
1731  // out of the range [0,1]
1732  for (std::list<FiniteElement*>::iterator it_list =
1733  segment_sorted_ele_pt[is].begin();
1734  it_list != segment_sorted_ele_pt[is].end();
1735  it_list++)
1736  {
1737  // Number of nodes in the segment
1738  const unsigned nnod = (*it_list)->nnode();
1739 
1740  // Get the first node of the current segment
1741  Node *first_node_pt = (*it_list)->node_pt(0);
1742  if(is_inverted[(*it_list)])
1743  {
1744  first_node_pt = (*it_list)->node_pt(nnod-1);
1745  }
1746 
1747  // Get the last node of the current segment
1748  Node *last_node_pt = (*it_list)->node_pt(nnod-1);
1749  if(is_inverted[(*it_list)])
1750  {
1751  last_node_pt = (*it_list)->node_pt(0);
1752  }
1753 
1754  // The z value for the first node
1755  Vector<double> zeta(1);
1756  first_node_pt->get_coordinates_on_boundary(b, zeta);
1757  if (zeta[0] < 0.0 || zeta[0] > 1.0)
1758  {
1759  std::ostringstream error_message;
1760  error_message
1761  <<"The boundary coordinate of the first node on boundary ("
1762  << b << ")\nand segment (" << is << ") is out of the "
1763  << "allowed values [0,1]\n"
1764  << "The node boundary coordinate: (" << zeta[0] << ")\n"
1765  << "The vertex coordinates are: ("
1766  << first_node_pt->x(0) << ", " << first_node_pt->x(1) << ")\n";
1767  throw OomphLibError(error_message.str(),
1768  OOMPH_CURRENT_FUNCTION,
1769  OOMPH_EXCEPTION_LOCATION);
1770  }
1771 
1772  // The z value for the last node
1773  last_node_pt->get_coordinates_on_boundary(b, zeta);
1774  if (zeta[0] < 0.0 || zeta[0] > 1.0)
1775  {
1776  std::ostringstream error_message;
1777  error_message
1778  <<"The boundary coordinate of the last node on boundary ("
1779  << b << ")\nand segment (" << is << ") is out of the "
1780  << "allowed values [0,1]\n"
1781  << "The node boundary coordinate: (" << zeta[0] << ")\n"
1782  << "The vertex coordinates are: ("
1783  << last_node_pt->x(0) << ", " << last_node_pt->x(1) << ")\n";
1784  throw OomphLibError(error_message.str(),
1785  OOMPH_CURRENT_FUNCTION,
1786  OOMPH_EXCEPTION_LOCATION);
1787  }
1788  }
1789 #endif // #ifdef PARANOID
1790 
1791  } // if (boundary_geom_object_pt(b)==0)
1792 
1793  } // for (is < nsegments)
1794 
1795  } // if (this != original_mesh_pt)
1796 
1797  // ------------------------------------------------------------------
1798  // Copy the corrected (possible reversed) info. to the containers of
1799  // the current mesh
1800  // ------------------------------------------------------------------
1801  // Check if there are segments of b boundary in this processor
1802  if (nsegments > 0)
1803  {
1804  // Copy the initial and final coordinates
1805  Boundary_initial_coordinate[b] =
1806  original_mesh_pt->boundary_initial_coordinate(b);
1807 
1808  Boundary_final_coordinate[b] =
1809  original_mesh_pt->boundary_final_coordinate(b);
1810 
1811  // The initial and final zeta coordinates (In case of a geometric
1812  // object those are the limits of the geom object)
1813  Boundary_initial_zeta_coordinate[b] =
1814  original_mesh_pt->boundary_initial_zeta_coordinate(b);
1815 
1816  Boundary_final_zeta_coordinate[b] =
1817  original_mesh_pt->boundary_final_zeta_coordinate(b);
1818 
1819  } // if (nsegments > 0)
1820 
1821  // Set the flag to indicate that the zeta values have been assigned
1822  // for the current boundary
1823  Assigned_segments_initial_zeta_values[b] = true;
1824 
1825  // Clean all the created face elements
1826  for (unsigned i = 0; i < nele; i++)
1827  {
1828  delete face_el_pt[i];
1829  face_el_pt[i] = 0;
1830  }
1831 
1832  }
1833 
1834  //======================================================================
1835  /// \short Compute the boundary segments connectivity for those
1836  /// boundaries that were splited during the distribution process
1837  /// and also the initial zeta values for each segment (the initial
1838  /// and final boundary nodes coordinates)
1839  //======================================================================
1840  template<class ELEMENT>
1843  const unsigned& b)
1844  {
1845  // ------------------------------------------------------------------
1846  // First: Get the face elements associated with the current boundary
1847  // ------------------------------------------------------------------
1848 
1849  // Get the communicator of the mesh
1850  OomphCommunicator* comm_pt = this->communicator_pt();
1851 
1852  // Get the number of processors
1853  const unsigned nproc = comm_pt->nproc();
1854  // Get the rank of the current processor
1855  const unsigned my_rank = comm_pt->my_rank();
1856 
1857  // Temporary storage for face elements
1858  Vector<FiniteElement*> all_face_ele_pt;
1859 
1860  // Flag to know whether we are working with an internal open curve
1861  // and then re-assign the initial and final zeta coordinates for
1862  // each segment (only used when the mesh is distributed)
1863  bool is_internal_boundary = false;
1864 
1865  // map to associate the face element to the bulk element, necessary
1866  // to attach halo face elements at both sides of each found segment
1867  std::map<FiniteElement*,FiniteElement*> face_to_bulk_element_pt;
1868 
1869  // Select the boundary face elements, using the criteria of highest
1870  // processor in charge and bottom-left element
1871  select_boundary_face_elements(all_face_ele_pt, b, is_internal_boundary,
1872  face_to_bulk_element_pt);
1873 
1874  // Get the number of face elements
1875  const unsigned n_all_face_ele = all_face_ele_pt.size();
1876 
1877  // ----------------------------------------------------------------
1878  // Second: Sort the face elements, only consider nonhalo elements
1879  // ----------------------------------------------------------------
1880 
1881  // A flag vector to mark those face elements that are considered as
1882  // halo in the current processor
1883  std::vector<bool> is_halo_face_element(n_all_face_ele, false);
1884 
1885  // Count the total number of non halo face elements
1886  unsigned nnon_halo_face_elements = 0;
1887 
1888  // Only mark the face elements as halo if the mesh is marked as
1889  // distributed
1890  for (unsigned ie = 0; ie < n_all_face_ele; ie++)
1891  {
1892  FiniteElement* face_ele_pt = all_face_ele_pt[ie];
1893  // Get the bulk element
1894  FiniteElement* tmp_bulk_ele_pt = face_to_bulk_element_pt[face_ele_pt];
1895  // Check if the bulk element is halo
1896  if (!tmp_bulk_ele_pt->is_halo())
1897  {
1898  // Set the flag for non halo element
1899  is_halo_face_element[ie] = false;
1900  // Increase the non halo elements counter
1901  nnon_halo_face_elements++;
1902  }
1903  else
1904  {
1905  // Mark the face element as halo
1906  is_halo_face_element[ie] = true;
1907  }
1908 
1909  } // for (ie < n_ele)
1910 
1911  // Get the total number of halo face elements
1912  const unsigned nhalo_face_element = n_all_face_ele - nnon_halo_face_elements;
1913 
1914  // The vector of list to store the "segments" that compound the
1915  // boundary (segments may appear only in a distributed mesh)
1916  Vector<std::list<FiniteElement*> > segment_sorted_ele_pt;
1917 
1918  // Number of already sorted face elements (only nonhalo elements for
1919  // a distributed mesh)
1920  unsigned nsorted_face_elements = 0;
1921 
1922  // Keep track of who's done (this apply to nonhalo only, remember we
1923  // are only working with halo elements)
1924  std::map<FiniteElement*, bool> done_el;
1925 
1926  // Keep track of which element is inverted (in distributed mesh the
1927  // elements may be inverted with respect to the segment they belong)
1928  std::map<FiniteElement*, bool> is_inverted;
1929 
1930  // Iterate until all possible segments have been created
1931  while(nsorted_face_elements < nnon_halo_face_elements)
1932  {
1933  // The ordered list of face elements (in a distributed mesh a
1934  // collection of contiguous face elements define a segment)
1935  std::list<FiniteElement*> sorted_el_pt;
1936  sorted_el_pt.clear();
1937 
1938 #ifdef PARANOID
1939  // Select an initial element for the segment (the first not done
1940  // nonhalo element)
1941  bool found_initial_face_element = false;
1942 #endif
1943 
1944  FiniteElement* ele_face_pt = 0;
1945 
1946  unsigned iface = 0;
1947  for (iface = 0; iface < n_all_face_ele; iface++)
1948  {
1949  if (!is_halo_face_element[iface])
1950  {
1951  ele_face_pt = all_face_ele_pt[iface];
1952  // If not done then take it as initial face element
1953  if (!done_el[ele_face_pt])
1954  {
1955 #ifdef PARANOID
1956  found_initial_face_element = true;
1957 #endif
1958  nsorted_face_elements++;
1959  iface++; // The next element number
1960  sorted_el_pt.push_back(ele_face_pt);
1961  // Mark as done
1962  done_el[ele_face_pt] = true;
1963  break;
1964  }
1965  }
1966  } // for (iface < nele)
1967 
1968 #ifdef PARANOID
1969  if (!found_initial_face_element)
1970  {
1971  std::ostringstream error_message;
1972  error_message
1973  <<"Could not find an initial face element for the current segment\n";
1974  // << "----- Possible memory leak -----\n";
1975  throw OomphLibError(error_message.str(),
1976  OOMPH_CURRENT_FUNCTION,
1977  OOMPH_EXCEPTION_LOCATION);
1978  }
1979 #endif
1980 
1981  // Number of nodes
1982  const unsigned nnod = ele_face_pt->nnode();
1983 
1984  // Left and rightmost nodes (the left and right nodes of the
1985  // current face element)
1986  Node* left_node_pt = ele_face_pt->node_pt(0);
1987  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
1988 
1989  // Continue iterating if a new face element has been added to the
1990  // list
1991  bool face_element_added = false;
1992 
1993  // While a new face element has been added to the set of sorted
1994  // face elements then re-iterate
1995  do
1996  {
1997  // Start from the next face element since we have already added
1998  // the previous one as the initial face element (any previous
1999  // face element had to be added on previous iterations)
2000  for (unsigned iiface = iface; iiface < n_all_face_ele; iiface++)
2001  {
2002  // Re-start flag
2003  face_element_added = false;
2004 
2005  // Get the candidate element
2006  ele_face_pt = all_face_ele_pt[iiface];
2007 
2008  // Check that the candidate element has not been done and is
2009  // not a halo element
2010  if (!(done_el[ele_face_pt] || is_halo_face_element[iiface]))
2011  {
2012  // Get the left and right nodes of the current element
2013  Node* local_left_node_pt = ele_face_pt->node_pt(0);
2014  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
2015 
2016  // New element fits at the left of segment and is not inverted
2017  if (left_node_pt == local_right_node_pt)
2018  {
2019  left_node_pt = local_left_node_pt;
2020  sorted_el_pt.push_front(ele_face_pt);
2021  is_inverted[ele_face_pt] = false;
2022  face_element_added = true;
2023  }
2024  // New element fits at the left of segment and is inverted
2025  else if (left_node_pt == local_left_node_pt)
2026  {
2027  left_node_pt = local_right_node_pt;
2028  sorted_el_pt.push_front(ele_face_pt);
2029  is_inverted[ele_face_pt] = true;
2030  face_element_added = true;
2031  }
2032  // New element fits on the right of segment and is not inverted
2033  else if (right_node_pt == local_left_node_pt)
2034  {
2035  right_node_pt = local_right_node_pt;
2036  sorted_el_pt.push_back(ele_face_pt);
2037  is_inverted[ele_face_pt] = false;
2038  face_element_added = true;
2039  }
2040  // New element fits on the right of segment and is inverted
2041  else if (right_node_pt == local_right_node_pt)
2042  {
2043  right_node_pt = local_left_node_pt;
2044  sorted_el_pt.push_back(ele_face_pt);
2045  is_inverted[ele_face_pt] = true;
2046  face_element_added = true;
2047  }
2048 
2049  if (face_element_added)
2050  {
2051  done_el[ele_face_pt] = true;
2052  nsorted_face_elements++;
2053  break;
2054  }
2055 
2056  } // if (!(done_el[ele_face_pt] || is_halo_face_element[iiface]))
2057  } // for (iiface<nnon_halo_face_element)
2058  }while(face_element_added &&
2059  (nsorted_face_elements < nnon_halo_face_elements));
2060 
2061  // Store the created segment in the vector of segments
2062  segment_sorted_ele_pt.push_back(sorted_el_pt);
2063 
2064  } // while(nsorted_face_elements < nnon_halo_face_elements);
2065 
2066  // -----------------------------------------------------------------
2067  // Third: We have the face elements sorted (in segments), now assign
2068  // boundary coordinates to the nodes in the segments, this is the
2069  // LOCAL boundary coordinate and further communication is needed to
2070  // compute the GLOBAL boundary coordinates
2071  // -----------------------------------------------------------------
2072 
2073  // Vector of sets that stores the nodes of each segment based on a
2074  // lexicographically order starting from the bottom left node of
2075  // each segment
2076  Vector<std::set<Node*> > segment_all_nodes_pt;
2077 
2078  // The number of segments in this processor
2079  const unsigned nsegments = segment_sorted_ele_pt.size();
2080 // DEBP(nsegments);
2081 
2082 #ifdef PARANOID
2083  if (nnon_halo_face_elements > 0 && nsegments == 0)
2084  {
2085  std::ostringstream error_message;
2086  error_message
2087  << "The number of segments is zero, but the number of nonhalo\n"
2088  << "elements is: (" << nnon_halo_face_elements << ")\n";
2089  throw OomphLibError(error_message.str(),
2090  OOMPH_CURRENT_FUNCTION,
2091  OOMPH_EXCEPTION_LOCATION);
2092  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
2093 #endif
2094 
2095  // The arclength of each segment in the current processor
2096  Vector<double> segment_arclength(nsegments);
2097 
2098  // The number of vertices of each segment
2099  Vector<unsigned> nvertices_per_segment(nsegments);
2100 
2101  // The initial zeta for the segment
2102  Vector<double> initial_zeta_segment(nsegments);
2103 
2104  // The final zeta for the segment
2105  Vector<double> final_zeta_segment(nsegments);
2106 
2107  // Go through all the segments and compute its ARCLENGTH (if the
2108  // boundary has a GeomObject associated then assign the initial and
2109  // final zeta values for the segment)
2110  for (unsigned is = 0; is < nsegments; is++)
2111  {
2112 #ifdef PARANOID
2113  if (segment_sorted_ele_pt[is].size() == 0)
2114  {
2115  std::ostringstream error_message;
2116  error_message
2117  << "The (" << is << ")-th segment has no elements\n";
2118  throw OomphLibError(error_message.str(),
2119  OOMPH_CURRENT_FUNCTION,
2120  OOMPH_EXCEPTION_LOCATION);
2121  } // if (segment_sorted_ele_pt[is].size() == 0)
2122 #endif
2123 
2124  // Get access to the first element on the segment
2125  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
2126 
2127  // Number of nodes
2128  const unsigned nnod = first_ele_pt->nnode();
2129 
2130  // Get the first node of the current segment
2131  Node *first_node_pt = first_ele_pt->node_pt(0);
2132  if (is_inverted[first_ele_pt])
2133  {
2134  first_node_pt = first_ele_pt->node_pt(nnod-1);
2135  }
2136 
2137  // Coordinates of left node
2138  double x_left = first_node_pt->x(0);
2139  double y_left = first_node_pt->x(1);
2140 
2141  // Initialise boundary coordinate (local boundary coordinate for
2142  // boundaries with more than one segment)
2143  Vector<double> zeta(1, 0.0);
2144 
2145  // If we have associated a GeomObject then it is not necessary to
2146  // compute the arclength, only read the values from the nodes at
2147  // the edges and set the initial and final zeta segment values
2148  if (this->boundary_geom_object_pt(b)!=0)
2149  {
2150  // Get the initial node coordinate
2151  first_node_pt->get_coordinates_on_boundary(b, zeta);
2152  // Set the initial zeta segment value
2153  initial_zeta_segment[is] = zeta[0];
2154 
2155  // Get access to the last element on the segment
2156  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
2157 
2158  // Get the last node of the current segment
2159  Node *last_node_pt = last_ele_pt->node_pt(nnod-1);
2160  if (is_inverted[last_ele_pt])
2161  {
2162  last_node_pt = last_ele_pt->node_pt(0);
2163  }
2164 
2165  // Get the final node coordinate
2166  last_node_pt->get_coordinates_on_boundary(b, zeta);
2167  // Set the final zeta segment value
2168  final_zeta_segment[is] = zeta[0];
2169 
2170  }
2171 
2172  // Sort the nodes in the segment (lexicographically bottom left
2173  // node)
2174  std::set<Node*> local_nodes_pt;
2175  // Insert the first node
2176  local_nodes_pt.insert(first_node_pt);
2177 
2178  // Now loop over nodes in order and increase the ARCLENGTH
2179  for (std::list<FiniteElement*>::iterator it =
2180  segment_sorted_ele_pt[is].begin();
2181  it != segment_sorted_ele_pt[is].end(); it++)
2182  {
2183  // Get the pointer to the element
2184  FiniteElement* el_pt = (*it);
2185 
2186  // Start node and increment
2187  unsigned k_nod = 1;
2188  int nod_diff = 1;
2189  // Access nodes in reverse?
2190  if (is_inverted[el_pt])
2191  {
2192  k_nod = nnod - 2;
2193  nod_diff = -1;
2194  }
2195 
2196  // Loop over nodes in the face element
2197  for (unsigned j = 1; j < nnod; j++)
2198  {
2199  Node* nod_pt = el_pt->node_pt(k_nod);
2200  k_nod += nod_diff;
2201 
2202  // Coordinates of right node
2203  double x_right = nod_pt->x(0);
2204  double y_right = nod_pt->x(1);
2205 
2206  // Increment boundary coordinate (the arclength)
2207  zeta[0] += sqrt(
2208  (x_right - x_left) * (x_right - x_left) + (y_right - y_left)
2209  * (y_right - y_left));
2210 
2211  // When we have a GeomObject associated to the boundary we already
2212  // know the zeta values for the nodes, there is no need to compute
2213  // the arclength
2214 // if (this->boundary_geom_object_pt(b)==0)
2215 // {
2216 // // Set boundary coordinate
2217 // // nod_pt->set_coordinates_on_boundary(b, zeta);
2218 // }
2219 
2220  // Increment reference coordinate
2221  x_left = x_right;
2222  y_left = y_right;
2223 
2224  // Get lexicographically bottom left node but only
2225  // use vertex nodes as candidates
2226  local_nodes_pt.insert(nod_pt);
2227 
2228  } // for (j < nnod)
2229 
2230  } // iterator over the elements in the segment
2231 
2232  // Info. to be passed to other processors
2233  // The initial arclength for the segment that goes after this depends
2234  // on the current segment arclength
2235  segment_arclength[is] = zeta[0];
2236 
2237  // Info. to be passed to the other processors
2238  // The initial vertex number for the segment that goes after this
2239  // depends on the current segment vertices number
2240  nvertices_per_segment[is] = local_nodes_pt.size();
2241 
2242  // Add the nodes for the corresponding segment in the container
2243  segment_all_nodes_pt.push_back(local_nodes_pt);
2244 
2245  // The attaching of the halo elements at both sides of the segments is
2246  // performed only if segments connectivity needs to be computed
2247 
2248  } // for (is < nsegments)
2249 
2250  // Container to store the number of vertices before each segment,
2251  // initialise to zero in case we have a non distributed boundary
2252  Vector<unsigned> nvertices_before_segment(nsegments,0);
2253 
2254  // Store the initial arclength for each segment of boundary in the
2255  // current processor, initalise to zero in case we have a non
2256  // distributed boundary
2257  Vector<double> initial_segment_arclength(nsegments,0.0);
2258 
2259  // Info. to be passed to other processors
2260  // If the boundary is distributed we need to know which processors does
2261  // have the initial and final segments, this helps to get the first and
2262  // last nodes coordinates (info. used to scale the bound coordinates)
2263 
2264  // Processors with the initial and final segment
2265  unsigned proc_with_initial_seg = 0;
2266  unsigned proc_with_final_seg = 0;
2267 
2268  // ... and the index of those segments (only of interest in the
2269  // processors that have the initial and final segments)
2270  unsigned initial_segment = 0;
2271  unsigned final_segment = 0;
2272 
2273  // Each segment needs to know whether it has to be inverted or not
2274  // Store whether a segment needs to be inverted or not
2275  Vector<unsigned> segment_inverted(nsegments);
2276 
2277  // Before attaching the halo elements create a copy of the data
2278  // structure without halo elements
2279  Vector<std::list<FiniteElement*> > segment_sorted_nonhalo_ele_pt(nsegments);
2280  for (unsigned is = 0; is < nsegments; is++)
2281  {
2282  for (std::list<FiniteElement*>::iterator it_seg =
2283  segment_sorted_ele_pt[is].begin();
2284  it_seg != segment_sorted_ele_pt[is].end();
2285  it_seg++)
2286  {
2287  segment_sorted_nonhalo_ele_pt[is].push_back((*it_seg));
2288  }
2289 
2290  } // for (is < nsegments)
2291 
2292  // --------------------------------------------------------------
2293  // Attach the halo elements at both sides of the segments
2294  for (unsigned is = 0; is < nsegments; is++)
2295  {
2296  // Get access to the first element on the segment
2297  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
2298 
2299  // Number of nodes
2300  const unsigned nnod = first_ele_pt->nnode();
2301 
2302  // Get the first node of the current segment
2303  Node *first_node_pt = first_ele_pt->node_pt(0);
2304  if (is_inverted[first_ele_pt])
2305  {
2306  first_node_pt = first_ele_pt->node_pt(nnod-1);
2307  }
2308 
2309  // Get access to the last element on the segment
2310  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
2311 
2312  // Get the last node of the current segment
2313  Node *last_node_pt = last_ele_pt->node_pt(nnod-1);
2314  if (is_inverted[last_ele_pt])
2315  {
2316  last_node_pt = last_ele_pt->node_pt(0);
2317  }
2318 
2319  // -----------------------------------------------------------------
2320  // Fourth: Now attach the halo elements to the left and right side
2321  // of each segment
2322  // -----------------------------------------------------------------
2323  bool attached_left_halo = false;
2324  bool attached_right_halo = false;
2325  if (nhalo_face_element > 0)
2326  {
2327  for (unsigned iiface = 0; iiface < n_all_face_ele; iiface++)
2328  {
2329  // Get the candidate element
2330  FiniteElement* halo_face_ele_pt = all_face_ele_pt[iiface];
2331 
2332  // Check that the element is a halo face element, we do not check
2333  // if the element has been already done since the halo elements
2334  // may be connected to more than one segment (2 at most), to the
2335  // left and right of different segments
2336  //
2337  // Segment k Halo Segment r
2338  // |---|---|---| |xxx| |---|---|---|
2339  //
2340  // Segment k Halo Segment r
2341  // |---|---|---|xxx|---|---|---|
2342  //
2343  if (is_halo_face_element[iiface])
2344  {
2345  // Get its left and right nodes
2346  Node* left_node_pt = halo_face_ele_pt->node_pt(0);
2347  Node* right_node_pt = halo_face_ele_pt->node_pt(nnod-1);
2348  // The halo element fits to the left of segment
2349  if (!attached_left_halo && (first_node_pt == right_node_pt ||
2350  first_node_pt == left_node_pt))
2351  {
2352  // Add the halo element to the left of the segment
2353  segment_sorted_ele_pt[is].push_front(halo_face_ele_pt);
2354 
2355  // Once a halo face element has been added to the left
2356  // mark as found halo to the left
2357  attached_left_halo = true;
2358  }
2359  // The halo element fits to the right of the segment
2360  else if (!attached_right_halo && (last_node_pt == left_node_pt ||
2361  last_node_pt == right_node_pt))
2362  {
2363  // Add the halo element to the right of the segment
2364  segment_sorted_ele_pt[is].push_back(halo_face_ele_pt);
2365  // Once a halo face element has been added to the right
2366  // mark as found halo to the right
2367  attached_right_halo = true;
2368  }
2369  // If we have already found elements to left and right then
2370  // break the loop
2371  if (attached_left_halo && attached_right_halo)
2372  {break;}
2373 
2374  } // if (is_halo_face_element[iiface])
2375 
2376  } // for (iiface < nel)
2377 
2378  } // if (nhalo_face_element > 0)
2379 
2380  } // for (is < nsegments)
2381 
2382  // The segments now have local coordinates assigned and halo
2383  // elements attached to them. Store that info. in the corresponding
2384  // data structures and be ready to send that info. to a root
2385  // processor. The root processor will be in charge of computing the
2386  // boundary coordinates for each segment of the boundary.
2387 
2388  // For each segment store the following information
2389  // --------------------------------------------------------------------
2390  // Stores the "rank" of the processor to the left of each segment,
2391  // zero if there is no processor to the left which states that the
2392  // segment is the first one on the boundary
2393  Vector<unsigned> left_processor_plus_one(nsegments);
2394 
2395  // Stores the "rank" of the processor to the right of each segment,
2396  // zero if there is no processor to the right which states that the
2397  // segment is the last one on the boundary
2398  Vector<unsigned> right_processor_plus_one(nsegments);
2399 
2400  // The id. of the halo element to the left of the segment, note that
2401  // this info. is not necessary if there is no processor to the left
2402  // of the segment
2403  Vector<unsigned> left_halo_element(nsegments);
2404 
2405  // The id. of the halo element to the right of the segment, note that
2406  // this info. is not necessary if there is no processor to the right
2407  // of the segment
2408  Vector<unsigned> right_halo_element(nsegments);
2409 
2410  // The id. of the haloed element to the left of the segment, note that
2411  // this info. is not necessary if there is no processor to the left
2412  // of the segment
2413  Vector<unsigned> left_haloed_element(nsegments);
2414 
2415  // The id. of the haloed element to the right of the segment, note
2416  // that this info. is not necessary if there is no processor to the
2417  // right of the segment
2418  Vector<unsigned> right_haloed_element(nsegments);
2419 
2420  // Go through all the segments and get the info.
2421  for (unsigned is = 0; is < nsegments; is++)
2422  {
2423  // Get access to the left most face element on the segment
2424  FiniteElement* left_face_ele_pt=segment_sorted_ele_pt[is].front();
2425 
2426  // Get the corresponding bulk element and check whether it is a halo
2427  // element or not
2428  FiniteElement* tmp_left_bulk_ele_pt =
2429  face_to_bulk_element_pt[left_face_ele_pt];
2430 
2431  // Check if the bulk element is halo
2432  if (tmp_left_bulk_ele_pt->is_halo())
2433  {
2434  // Then store the corresponding info.
2435  int left_proc = tmp_left_bulk_ele_pt->non_halo_proc_ID();
2436 #ifdef PARANOID
2437  if (left_proc < 0)
2438  {
2439  std::ostringstream error_message;
2440  error_message
2441  << "The current bulk element (left) is marked as halo but "
2442  << "the processor holding\nthe non-halo counterpart is "
2443  << "negative!\n";
2444  throw OomphLibError(error_message.str(),
2445  OOMPH_CURRENT_FUNCTION,
2446  OOMPH_EXCEPTION_LOCATION);
2447  }
2448 #endif
2449  // The processor "rank" to the left
2450  unsigned left_processor = static_cast<unsigned>(left_proc);
2451  left_processor_plus_one[is] = left_processor + 1;
2452 
2453  // Now get the id of the halo element to the left
2454  GeneralisedElement *left_element_pt = tmp_left_bulk_ele_pt;
2455 
2456  // Get the halo elements with left processor
2457  Vector<GeneralisedElement*> left_halo_element_pt =
2458  this->halo_element_pt(left_processor);
2459 
2460 #ifdef PARANOID
2461  // Flag to state that the halo element was found
2462  bool left_halo_element_found = false;
2463 #endif
2464 
2465  const unsigned n_halo_left = left_halo_element_pt.size();
2466  for (unsigned lh = 0; lh < n_halo_left; lh++)
2467  {
2468  if (left_element_pt == left_halo_element_pt[lh])
2469  {
2470  left_halo_element[is] = lh;
2471 #ifdef PARANOID
2472  left_halo_element_found = true;
2473 #endif
2474  break;
2475  }
2476  } // for (lh < n_halo_left)
2477 
2478 #ifdef PARANOID
2479  if (!left_halo_element_found)
2480  {
2481  std::ostringstream error_message;
2482  error_message
2483  << "The current bulk element (left) marked as halo was "
2484  << "not found in the vector of halo\nelements associated "
2485  << "with the (" << left_processor << ") processor.\n\n";
2486  throw OomphLibError(error_message.str(),
2487  OOMPH_CURRENT_FUNCTION,
2488  OOMPH_EXCEPTION_LOCATION);
2489  } // if (!left_halo_element_found)
2490 #endif
2491 
2492  // Get the left-most nonhalo element (use the backup list of
2493  // nonhalo elements)
2494  left_face_ele_pt = segment_sorted_nonhalo_ele_pt[is].front();
2495 
2496  // Get the corresponding bulk element
2497  tmp_left_bulk_ele_pt = face_to_bulk_element_pt[left_face_ele_pt];
2498 
2499 #ifdef PARANOID
2500  // This element should not be marked as halo
2501  if (tmp_left_bulk_ele_pt->is_halo())
2502  {
2503  std::ostringstream error_message;
2504  error_message
2505  << "The bulk element represetation of the left-most nonhalo face\n"
2506  << "element of the current segment ("<<is<<") is marked as halo,\n"
2507  << "but the face element created from it is nonhalo\n";
2508  throw OomphLibError(error_message.str(),
2509  OOMPH_CURRENT_FUNCTION,
2510  OOMPH_EXCEPTION_LOCATION);
2511  } // if (tmp_left_bulk_ele_pt->is_halo())
2512 #endif
2513 
2514  // Cast from "FiniteElement*" to "GeneralisedElement*" to be able
2515  // to search in the haloed vector
2516  left_element_pt = tmp_left_bulk_ele_pt;
2517 
2518 #ifdef PARANOID
2519  // Flag to state that the haloed element was found
2520  bool left_haloed_element_found = false;
2521 #endif
2522 
2523  // Now get the id for the haloed element to the left, get the
2524  // haloed elements from the processor to the left
2525  Vector<GeneralisedElement*> left_haloed_element_pt =
2526  this->haloed_element_pt(left_processor);
2527 
2528  const unsigned nhaloed_left = left_haloed_element_pt.size();
2529  for (unsigned lhd = 0; lhd < nhaloed_left; lhd++)
2530  {
2531  if (left_element_pt == left_haloed_element_pt[lhd])
2532  {
2533  left_haloed_element[is] = lhd;
2534 #ifdef PARANOID
2535  left_haloed_element_found = true;
2536 #endif
2537  break;
2538  }
2539  } // for (lhd < nhaloed_left)
2540 
2541 #ifdef PARANOID
2542  if (!left_haloed_element_found)
2543  {
2544  std::ostringstream error_message;
2545  error_message
2546  << "The current bulk element (left) marked as haloed was "
2547  << "not found in the vector of haloed\nelements associated "
2548  << "with processor ("<< left_processor << ").\n";
2549  throw OomphLibError(error_message.str(),
2550  OOMPH_CURRENT_FUNCTION,
2551  OOMPH_EXCEPTION_LOCATION);
2552  }
2553 #endif
2554  } // if (tmp_left_bulk_ele_pt->is_halo())
2555  else
2556  {
2557  // If not halo then state the info. to indicate that
2558  left_processor_plus_one[is] = 0;
2559  // Null this info.
2560  left_halo_element[is] = 0;
2561  // Null this info.
2562  left_haloed_element[is] = 0;
2563  }
2564 
2565  // Get access to the right most face element on the segment
2566  FiniteElement* right_face_ele_pt = segment_sorted_ele_pt[is].back();
2567 
2568  // Get the corresponding bulk element and check whether it is
2569  // a halo element or not
2570  FiniteElement* tmp_right_bulk_ele_pt =
2571  face_to_bulk_element_pt[right_face_ele_pt];
2572 
2573  // Check if the bulk element is halo
2574  if (tmp_right_bulk_ele_pt->is_halo())
2575  {
2576  // Then store the corresponding info.
2577  int right_proc = tmp_right_bulk_ele_pt->non_halo_proc_ID();
2578 #ifdef PARANOID
2579  if (right_proc < 0)
2580  {
2581  std::ostringstream error_message;
2582  error_message
2583  << "The current bulk element (right) is marked as halo but "
2584  << "the processor holding\nthe non-halo counterpart is "
2585  << "negative!\n";
2586  throw OomphLibError(error_message.str(),
2587  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
2588  OOMPH_EXCEPTION_LOCATION);
2589  }
2590 #endif
2591  // The processor "rank" to the right
2592  unsigned right_processor = static_cast<unsigned>(right_proc);
2593  right_processor_plus_one[is] = right_processor + 1;
2594 
2595  // Now get the id of the halo element to the right
2596  GeneralisedElement *right_element_pt = tmp_right_bulk_ele_pt;
2597 
2598  // Get the halo elements with right processor
2599  Vector<GeneralisedElement*> right_halo_element_pt =
2600  this->halo_element_pt(right_processor);
2601 
2602 #ifdef PARANOID
2603  // Flag to state that the halo element was found
2604  bool right_halo_element_found = false;
2605 #endif
2606 
2607  const unsigned nhalo_right = right_halo_element_pt.size();
2608  for (unsigned rh = 0; rh < nhalo_right; rh++)
2609  {
2610  if (right_element_pt == right_halo_element_pt[rh])
2611  {
2612  right_halo_element[is] = rh;
2613 #ifdef PARANOID
2614  right_halo_element_found = true;
2615 #endif
2616  break;
2617  }
2618  } // for (rh < nhalo_right)
2619 #ifdef PARANOID
2620  if (!right_halo_element_found)
2621  {
2622  std::ostringstream error_message;
2623  error_message
2624  << "The current bulk element (right) marked as halo was not "
2625  << "found in the vector of halo\nelements associated with "
2626  << "the (" << right_processor << ") processor.\n\n";
2627  throw OomphLibError(error_message.str(),
2628  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
2629  OOMPH_EXCEPTION_LOCATION);
2630  }
2631 #endif
2632 
2633  // Get the right-most nonhalo element (use the backup list of
2634  // nonhalo elements)
2635  right_face_ele_pt = segment_sorted_nonhalo_ele_pt[is].back();
2636 
2637  // Get the corresponding bulk element
2638  tmp_right_bulk_ele_pt=face_to_bulk_element_pt[right_face_ele_pt];
2639 #ifdef PARANOID
2640  // This element should not be marked as halo
2641  if (tmp_right_bulk_ele_pt->is_halo())
2642  {
2643  std::ostringstream error_message;
2644  error_message
2645  << "The bulk element represetation of the right-most nonhalo face\n"
2646  << "element of the current segment ("<<is<<") is marked as halo,\n"
2647  << "but the face element created from it is nonhalo\n";
2648  throw OomphLibError(error_message.str(),
2649  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
2650  OOMPH_EXCEPTION_LOCATION);
2651  } // if (tmp_right_bulk_ele_pt->is_halo())
2652 #endif
2653 
2654  // Cast from "FiniteElement*" to "GeneralisedElement*" to be able
2655  // to search in the haloed vector
2656  right_element_pt = tmp_right_bulk_ele_pt;
2657 
2658 #ifdef PARANOID
2659  // Flag to state that the haloed element was found
2660  bool right_haloed_element_found = false;
2661 #endif
2662 
2663  // Now get the id for the haloed element to the right
2664  Vector<GeneralisedElement*> right_haloed_element_pt =
2665  this->haloed_element_pt(right_processor);
2666 
2667  const unsigned nhaloed_right = right_haloed_element_pt.size();
2668  for (unsigned rhd = 0; rhd < nhaloed_right; rhd++)
2669  {
2670  if (right_element_pt == right_haloed_element_pt[rhd])
2671  {
2672  right_haloed_element[is] = rhd;
2673 #ifdef PARANOID
2674  right_haloed_element_found = true;
2675 #endif
2676  break;
2677  }
2678  } // for (rhd < nhaloed_right)
2679 
2680 #ifdef PARANOID
2681  if (!right_haloed_element_found)
2682  {
2683  std::ostringstream error_message;
2684  error_message
2685  << "The current bulk element (right) marked as haloed was not "
2686  << "found in the vector of haloed\nelements associated with "
2687  << "the ("<< right_processor << ") processor.\n\n";
2688  throw OomphLibError(error_message.str(),
2689  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
2690  OOMPH_EXCEPTION_LOCATION);
2691  }
2692 #endif
2693 
2694  } // if (tmp_right_bulk_ele_pt->is_halo())
2695  else
2696  {
2697  // If not halo then state the info. to indicate that
2698  right_processor_plus_one[is] = 0;
2699  // Null this info.
2700  right_halo_element[is] = 0;
2701  // Null this info.
2702  right_haloed_element[is] = 0;
2703  }
2704 
2705  } // for (is < nsegments). Used to get the halo info. of the
2706  // segments
2707 
2708  // Now we have all the info. to be sent to the root processor and
2709  // compute the correct (global) boundary coordinates for the current
2710  // boundary
2711 
2712  // The root processor will be in charge of performing the computing
2713  // of the coordinate values along the boundary, all the other
2714  // processors only send their info. and wait for receiving the new
2715  // starting values for each of its segments
2716 
2717  // Choose the root processor
2718  const unsigned root_processor = 0;
2719  // ------------------------------------------------------------------
2720  // Starts the MPI stage
2721 
2722  // The root processor receives the number of segments of each
2723  // processor associated to the current boundary
2724  Vector<unsigned> root_nsegments_per_processor(nproc);
2725  unsigned nsegments_mpi = nsegments;
2726  MPI_Gather(&nsegments_mpi, 1, MPI_UNSIGNED,
2727  &root_nsegments_per_processor[0], 1, MPI_UNSIGNED,
2728  root_processor, comm_pt->mpi_comm());
2729 
2730  // Package the info. and prepare it to be sent
2731  // For the packaged info. we send 7 data per each segment, the indexes
2732  // are as follow; 0 left proc, 1 right proc, 2 left halo, 3 right
2733  // halo, 4 left haloed, 5 right haloed and 6 for nvertices per
2734  // segment
2735  // The size of the package (unsigned)
2736  const unsigned spu = 7;
2737  Vector<unsigned> flat_packed_unsigned_send_data(nsegments*spu);
2738  for (unsigned is = 0; is < nsegments; is++)
2739  {
2740  flat_packed_unsigned_send_data[(spu*is)+0]=left_processor_plus_one[is];
2741  flat_packed_unsigned_send_data[(spu*is)+1]=right_processor_plus_one[is];
2742  flat_packed_unsigned_send_data[(spu*is)+2]=left_halo_element[is];
2743  flat_packed_unsigned_send_data[(spu*is)+3]=right_halo_element[is];
2744  flat_packed_unsigned_send_data[(spu*is)+4]=left_haloed_element[is];
2745  flat_packed_unsigned_send_data[(spu*is)+5]=right_haloed_element[is];
2746  flat_packed_unsigned_send_data[(spu*is)+6]=nvertices_per_segment[is];
2747  }
2748 
2749  // How many data will this processor send
2750  const unsigned nudata_to_send = flat_packed_unsigned_send_data.size();
2751 
2752  // How many data does the root processor will receive from each
2753  // processor
2754  Vector<int> root_nudata_to_receive(nproc,0);
2755  // Total number of data to receive from all processors
2756  unsigned root_nutotal_data_receive = 0;
2757  for (unsigned ip = 0; ip < nproc; ip++)
2758  {
2759  // Compute the number of data the root processor will receive from
2760  // each processor
2761  root_nudata_to_receive[ip] = root_nsegments_per_processor[ip] * spu;
2762  // Add on the total number of data to receive
2763  root_nutotal_data_receive+= root_nudata_to_receive[ip];
2764  }
2765 
2766  // Stores and compute the offsets (in root) for the data received
2767  // from each processor
2768  Vector<int> root_uoffsets_receive(nproc,0);
2769  root_uoffsets_receive[0] = 0;
2770  for (unsigned ip = 1; ip < nproc; ip++)
2771  {
2772  // Compute the offset to store the values from each processor
2773  root_uoffsets_receive[ip] =
2774  root_uoffsets_receive[ip-1] + root_nudata_to_receive[ip-1];
2775  }
2776 
2777  // Create at least one entry so we don't get a seg fault below
2778  if (flat_packed_unsigned_send_data.size()==0)
2779  {
2780  flat_packed_unsigned_send_data.resize(1);
2781  }
2782 
2783  // Vector where to receive the info.
2784  Vector<unsigned> flat_packed_unsigned_receive_data(
2785  root_nutotal_data_receive);
2786  if (my_rank!=root_processor)
2787  {
2788  // Create at least one entry so we don't get a seg fault below
2789  if (flat_packed_unsigned_receive_data.size()==0)
2790  {
2791  flat_packed_unsigned_receive_data.resize(1);
2792  }
2793  } // if (my_rank!=root_processor)
2794 
2795  MPI_Gatherv(&flat_packed_unsigned_send_data[0], // Flat package to
2796  // send info. from
2797  // each processor
2798  nudata_to_send, // Total number of data to send from
2799  // each processor
2800  MPI_UNSIGNED,
2801  &flat_packed_unsigned_receive_data[0], // Container
2802  // where to
2803  // receive the
2804  // info. from all
2805  // the processors
2806  &root_nudata_to_receive[0], // Number of data to receive
2807  // from each processor
2808  &root_uoffsets_receive[0], // The offset to store the
2809  // info. from each processor
2810  MPI_UNSIGNED,
2811  root_processor, //The processor that receives all the
2812  //info.
2813  comm_pt->mpi_comm());
2814 
2815  // Clear the flat package to send
2816  flat_packed_unsigned_send_data.clear();
2817  flat_packed_unsigned_send_data.resize(0);
2818 
2819  // Package the info. and prepare it to be sent
2820  // For the packaged info. we send 1 data per each segment which is
2821  // at the moment the arclength of each segment
2822  // The size of the package
2823  const unsigned spd = 1;
2824  Vector<double> flat_packed_double_send_data(nsegments*spd);
2825  for (unsigned is = 0; is < nsegments; is++)
2826  {
2827  flat_packed_double_send_data[(spd*is)+0]=segment_arclength[is];
2828  }
2829 
2830  // How many data will this processor send
2831  const unsigned nddata_to_send = flat_packed_double_send_data.size();
2832  // How many data does the root processor will receive from each
2833  // processor
2834  Vector<int> root_nddata_to_receive(nproc,0);
2835  // Total number of data to receive from all processors
2836  unsigned root_ndtotal_data_receive = 0;
2837  for (unsigned ip =0; ip < nproc; ip++)
2838  {
2839  root_nddata_to_receive[ip] = root_nsegments_per_processor[ip] * spd;
2840  root_ndtotal_data_receive+= root_nddata_to_receive[ip];
2841  }
2842 
2843  // Stores and compute the offsets for the data received from each
2844  // processor
2845  Vector<int> root_doffsets_receive(nproc,0);
2846  root_doffsets_receive[0] = 0;
2847  for (unsigned ip = 1; ip < nproc; ip++)
2848  {
2849  // Compute the offset to store the values from each processor
2850  root_doffsets_receive[ip] =
2851  root_doffsets_receive[ip-1] + root_nddata_to_receive[ip-1];
2852  }
2853 
2854  // Create at least one entry so we don't get a seg fault below
2855  if (flat_packed_double_send_data.size()==0)
2856  {
2857  flat_packed_double_send_data.resize(1);
2858  }
2859 
2860  // Vector where to receive the info.
2861  Vector<double> flat_packed_double_receive_data(root_ndtotal_data_receive);
2862  if (my_rank!=root_processor)
2863  {
2864  // Create at least one entry so we don't get a seg fault below
2865  if (flat_packed_double_receive_data.size()==0)
2866  {
2867  flat_packed_double_receive_data.resize(1);
2868  }
2869  }
2870 
2871  MPI_Gatherv(&flat_packed_double_send_data[0], // Flat package to
2872  // send info. from
2873  // each processor
2874  nddata_to_send, // Total number of data to send from
2875  // each processor
2876  MPI_DOUBLE,
2877  &flat_packed_double_receive_data[0], // Container where
2878  // to receive the
2879  // info. from all
2880  // the processors
2881  &root_nddata_to_receive[0], // Number of data to receive
2882  // from each processor
2883  &root_doffsets_receive[0], // The offset to store the
2884  // info. from each processor
2885  MPI_DOUBLE,
2886  root_processor, //The processor that receives all the
2887  //info.
2888  comm_pt->mpi_comm());
2889 
2890  // Clear the flat package to send
2891  flat_packed_double_send_data.clear();
2892  flat_packed_double_send_data.resize(0);
2893 
2894  // The next three containers are only used by the root processor at
2895  // the end of its computations but it is necessary that all the
2896  // processors know them when calling back the info.
2897 
2898  // Container that state the initial arclength for each segments
2899  // of each processor
2900  Vector<Vector<double> > root_initial_segment_arclength(nproc);
2901 
2902  // Container that state the number of vertices before each segment
2903  // in a given processor
2904  Vector<Vector<unsigned> > root_nvertices_before_segment(nproc);
2905 
2906  // The root processor needs to tell the other processor if it was
2907  // necessary to reverse a segment. Each processor should therefore
2908  // invert the face elements that compose every segment that was
2909  // inverted by the root processor
2910  Vector<Vector<unsigned> > root_segment_inverted(nproc);
2911 
2912  // Used to store the accumulated arclength, used at the end of
2913  // communications to store the total arclength
2914  double root_accumulated_arclength = 0.0;
2915 
2916  // Store the accumulated number of vertices, it means the total number
2917  // of vertices before each segment (counter)
2918  unsigned root_accumulated_vertices_before_segment = 0;
2919 
2920  // The root processor is in charge of performing the connections
2921  // of the segments that define the complete boundary
2922  if (my_rank == root_processor)
2923  {
2924  // From the flat packaged received data re-create the data
2925  // structures storing the info. regarding the connectivity of the
2926  // segments, the number of vertices per segment and the local
2927  // arclength of each segment
2928 
2929  // Stores the "rank" of the processor to the left of each segment,
2930  // zero if there is no processor to the left which states that the
2931  // segment is the first one on the boundary
2932  Vector<Vector<unsigned> > root_left_processor_plus_one(nproc);
2933 
2934  // Stores the "rank" of the processor to the right of each segment,
2935  // zero if there is no processor to the right which states that the
2936  // segment is the last one on the boundary
2937  Vector<Vector<unsigned> > root_right_processor_plus_one(nproc);
2938 
2939  // The id. of the halo element to the left of the segment, note that
2940  // this info. is not necessary if there is no processor to the left
2941  // of the segment or if the processor has no info about the boundary
2942  Vector<Vector<unsigned> > root_left_halo_element(nproc);
2943 
2944  // The id. of the halo element to the right of the segment, note
2945  // that this info. is not necessary if there is no processor to
2946  // the right of the segment or if the processor has no info about
2947  // the boundary
2948  Vector<Vector<unsigned> > root_right_halo_element(nproc);
2949 
2950  // The id. of the haloed element to the left of the segment, note
2951  // that this info. is not necessary if there is no processor to
2952  // the left of the segment or if the processor has no info about
2953  // the boundary
2954  Vector<Vector<unsigned> > root_left_haloed_element(nproc);
2955 
2956  // The id. of the haloed element to the right of the segment, note
2957  // that this info. is not necessary if there is no processor to the
2958  // right of the segment or if the processor has no info about the
2959  // boundary
2960  Vector<Vector<unsigned> > root_right_haloed_element(nproc);
2961 
2962  // The number of vertices per segment in each processor
2963  Vector<Vector<unsigned> > root_nvertices_per_segment(nproc);
2964 
2965  // The arclength of each of the segments in the processors
2966  Vector<Vector<double> > root_segment_arclength(nproc);
2967 
2968  unsigned ucounter = 0;
2969  unsigned dcounter = 0;
2970  for (unsigned ip = 0; ip < nproc; ip++)
2971  {
2972  // Get the number of segments in the current processor
2973  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
2974 
2975  root_left_processor_plus_one[ip].resize(nsegs_iproc);
2976  root_right_processor_plus_one[ip].resize(nsegs_iproc);
2977  root_left_halo_element[ip].resize(nsegs_iproc);
2978  root_right_halo_element[ip].resize(nsegs_iproc);
2979  root_left_haloed_element[ip].resize(nsegs_iproc);
2980  root_right_haloed_element[ip].resize(nsegs_iproc);
2981 
2982  // Additional info.
2983  root_nvertices_per_segment[ip].resize(nsegs_iproc);
2984  root_segment_arclength[ip].resize(nsegs_iproc);
2985  root_segment_inverted[ip].resize(nsegs_iproc);
2986 
2987  // Extract the info. from the BIG package received from all
2988  // processors
2989  for(unsigned is = 0; is < nsegs_iproc; is++)
2990  {
2991  // ------ The flat unsigned package ------
2992  root_left_processor_plus_one[ip][is] =
2993  flat_packed_unsigned_receive_data[ucounter++];
2994  root_right_processor_plus_one[ip][is] =
2995  flat_packed_unsigned_receive_data[ucounter++];
2996  root_left_halo_element[ip][is] =
2997  flat_packed_unsigned_receive_data[ucounter++];
2998  root_right_halo_element[ip][is] =
2999  flat_packed_unsigned_receive_data[ucounter++];
3000  root_left_haloed_element[ip][is] =
3001  flat_packed_unsigned_receive_data[ucounter++];
3002  root_right_haloed_element[ip][is] =
3003  flat_packed_unsigned_receive_data[ucounter++];
3004  root_nvertices_per_segment[ip][is] =
3005  flat_packed_unsigned_receive_data[ucounter++];
3006 
3007  // ------ The flat double package ------
3008  root_segment_arclength[ip][is] =
3009  flat_packed_double_receive_data[dcounter++];
3010  } // for (is < nsegs_iproc)
3011  } // for (ip < nproc)
3012 
3013  // Now the root processor has all the info. to find out the
3014  // CONNECTIVITY of the segments in each processor
3015 
3016  // Container that stores the info. related with the connectivity
3017  // of the segments of each processor
3018  Vector<Vector<int> > left_connected_segment_plus_one(nproc);
3019  Vector<Vector<int> > right_connected_segment_plus_one(nproc);
3020  for (unsigned ip = 0; ip < nproc; ip++)
3021  {
3022  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3023  left_connected_segment_plus_one[ip].resize(nsegs_iproc,-1);
3024  right_connected_segment_plus_one[ip].resize(nsegs_iproc,-1);
3025  } // for (ip < nprocs)
3026 
3027  // In charge of storing the connectivity of the segments, the pair
3028  // indicates the processor and the segment number
3029  std::list<std::pair<unsigned, unsigned> > proc_seg_connectivity;
3030  proc_seg_connectivity.clear();
3031 
3032  // Done segments on processor
3033  std::map<std::pair<unsigned, unsigned>, bool> done_segment;
3034 
3035  // Take the first segment of the first processor with segments and
3036  // add it to the list of segments
3037  unsigned left_proc = 0;
3038  unsigned right_proc = 0;
3039  unsigned left_seg = 0;
3040  unsigned right_seg = 0;
3041  for (unsigned ip = 0; ip < nproc; ip++)
3042  {
3043  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3044  if (nsegs_iproc > 0)
3045  {
3046  right_proc = left_proc = ip;
3047  right_seg = left_seg = 0;
3048  break; // Break because it is the first processor with at
3049  // least one segment
3050  }
3051  } // for (ip < nproc)
3052 
3053  // ... and add it to the list of segments
3054  std::pair<unsigned, unsigned> add_segment =
3055  std::make_pair(left_proc, left_seg);
3056  done_segment[add_segment] = true;
3057  proc_seg_connectivity.push_back(add_segment);
3058 
3059  // Flags to indicate when a segment was added to the left or right
3060  // of the current list of segments
3061  bool added_segment_to_the_left = false;
3062  bool added_segment_to_the_right = false;
3063 
3064  do // while(added_segment_to_the_left || added_segment_to_the_right)
3065  {
3066  // Read the left-most processor and segment in the list
3067  std::pair<unsigned, unsigned> left_pair =
3068  proc_seg_connectivity.front();
3069  left_proc = left_pair.first;
3070  left_seg = left_pair.second;
3071 
3072  // Get the processor number to the left of the left-most
3073  // segment in the list
3074  const unsigned new_left_proc =
3075  root_left_processor_plus_one[left_proc][left_seg];
3076 
3077  if (new_left_proc != 0)
3078  {
3079  // Initialise flag
3080  added_segment_to_the_left = false;
3081  // Get the left halo element id
3082  const unsigned left_halo_id =
3083  root_left_halo_element[left_proc][left_seg];
3084 
3085  // Get the left haloed element id
3086  const unsigned left_haloed_id =
3087  root_left_haloed_element[left_proc][left_seg];
3088 
3089  // Go through the segments on the new left processor and look
3090  // for the corresponding left_halo_id in the haloed_ids
3091  const unsigned nsegs_new_left_proc =
3092  root_nsegments_per_processor[new_left_proc-1];
3093 
3094  for (unsigned ils = 0; ils < nsegs_new_left_proc; ils++)
3095  {
3096  std::pair<unsigned, unsigned> candidate_seg =
3097  std::make_pair(new_left_proc-1, ils);
3098 
3099  // Check that the segment has not been already added
3100  if (!done_segment[candidate_seg])
3101  {
3102  // Only consider the segments on new left processor which
3103  // right processor is the current one (left_proc)
3104  const unsigned right_proc_of_new_left_proc =
3105  root_right_processor_plus_one[new_left_proc-1][ils];
3106  // Also get the left_proc_of_new_left_proc (in case that it
3107  // be necessary to invert the segment)
3108  const unsigned left_proc_of_new_left_proc =
3109  root_left_processor_plus_one[new_left_proc-1][ils];
3110  // Check the not inverted case (to the left and not
3111  // inverted)
3112  if (right_proc_of_new_left_proc != 0 &&
3113  right_proc_of_new_left_proc-1 == left_proc)
3114  {
3115  // Get the haloed/haloed element id of the current segment
3116  // in the new left processor and compare it to the
3117  // halo/haloed element id of the left_processor
3118  const unsigned right_halo_id =
3119  root_right_halo_element[new_left_proc-1][ils];
3120  const unsigned right_haloed_id =
3121  root_right_haloed_element[new_left_proc-1][ils];
3122  if (left_halo_id == right_haloed_id &&
3123  left_haloed_id == right_halo_id)
3124  {
3125  // We have a match of the segments (store the segment
3126  // number plus one on the processor to the left)
3127  left_connected_segment_plus_one[left_proc][left_seg]=
3128  ils+1;
3129  // Add the pair to the connectivity list
3130  proc_seg_connectivity.push_front(candidate_seg);
3131  added_segment_to_the_left = true;
3132  break;
3133  }
3134  } // if (right_proc_of_new_left_proc-1 == left_proc)
3135 
3136  // Check the inverted case (to the left and inverted)
3137  if (left_proc_of_new_left_proc != 0 &&
3138  left_proc_of_new_left_proc-1 == left_proc)
3139  {
3140  // Get the haloed element id of the current segment
3141  // (inverted version) in the new left processor and
3142  // compare it to the halo element id of the left_processor
3143  const unsigned inv_left_halo_id =
3144  root_left_halo_element[new_left_proc-1][ils];
3145  const unsigned inv_left_haloed_id =
3146  root_left_haloed_element[new_left_proc-1][ils];
3147  if (left_halo_id == inv_left_haloed_id &&
3148  left_haloed_id == inv_left_halo_id)
3149  {
3150  // We have a match of the segments (store the segment
3151  // number plus one on the processor to the left)
3152  left_connected_segment_plus_one[left_proc][left_seg]=
3153  ils+1;
3154  // Add the pair to the connectivity list
3155  proc_seg_connectivity.push_front(candidate_seg);
3156 
3157  // In addition to the connectivity we need to invert the
3158  // segment (the information)
3159  const unsigned tmp_proc =
3160  root_left_processor_plus_one[new_left_proc-1][ils];
3161  const unsigned tmp_halo =
3162  root_left_halo_element[new_left_proc-1][ils];
3163  const unsigned tmp_haloed =
3164  root_left_haloed_element[new_left_proc-1][ils];
3165 
3166  root_left_processor_plus_one[new_left_proc-1][ils] =
3167  root_right_processor_plus_one[new_left_proc-1][ils];
3168  root_left_halo_element[new_left_proc-1][ils] =
3169  root_right_halo_element[new_left_proc-1][ils];
3170  root_left_haloed_element[new_left_proc-1][ils] =
3171  root_right_haloed_element[new_left_proc-1][ils];
3172 
3173  root_right_processor_plus_one[new_left_proc-1][ils] =
3174  tmp_proc;
3175  root_right_halo_element[new_left_proc-1][ils]=tmp_halo;
3176  root_right_haloed_element[new_left_proc-1][ils] =
3177  tmp_haloed;
3178 
3179  // ... and mark the segment as inverted in the root
3180  // processor to inform back to the owner processor
3181  root_segment_inverted[new_left_proc-1][ils] = 1;
3182 
3183  added_segment_to_the_left = true;
3184  break;
3185  }
3186  } // if (left_proc_of_new_left_proc-1 == left_proc)
3187  } // if (!done_segment[candidate_segment])
3188  } // for (ils < nsegs_new_left_proc)
3189 
3190 #ifdef PARANOID
3191  if (!added_segment_to_the_left)
3192  {
3193  std::ostringstream error_message;
3194  error_message
3195  << "The corresponding processor and segment to the left of "
3196  << "the current left\nmost segment was not found\n";
3197  throw OomphLibError(error_message.str(),
3198  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
3199  OOMPH_EXCEPTION_LOCATION);
3200  }
3201 #endif
3202  } // if (new_left_proc != 0)
3203  else
3204  {
3205  // No more segments to the left
3206  added_segment_to_the_left = false;
3207  }
3208 
3209  // Read the info. of the right processor and the right segment
3210  std::pair<unsigned, unsigned> right_pair =
3211  proc_seg_connectivity.back();
3212  right_proc = right_pair.first;
3213  right_seg = right_pair.second;
3214 
3215  // Get the processor number to the right of the right-most
3216  // segment in the list
3217  const unsigned new_right_proc =
3218  root_right_processor_plus_one[right_proc][right_seg];
3219 
3220  if (new_right_proc != 0)
3221  {
3222  // Initialise flag
3223  added_segment_to_the_right = false;
3224  // Get the right halo element id
3225  const unsigned right_halo_id =
3226  root_right_halo_element[right_proc][right_seg];
3227 
3228  // Get the right halo element id
3229  const unsigned right_haloed_id =
3230  root_right_haloed_element[right_proc][right_seg];
3231 
3232  // Go through the segments on the new right processor and look
3233  // for the corresponding right_halo_id in the haloed_ids
3234  const unsigned nsegs_new_right_proc =
3235  root_nsegments_per_processor[new_right_proc-1];
3236 
3237  for (unsigned irs = 0; irs < nsegs_new_right_proc; irs++)
3238  {
3239  std::pair<unsigned, unsigned> candidate_seg =
3240  std::make_pair(new_right_proc-1, irs);
3241 
3242  // Check that the segment has not been already added
3243  if (!done_segment[candidate_seg])
3244  {
3245  // Only consider the segments on new right processor which
3246  // left processor is the current one (right_proc)
3247  const unsigned left_proc_of_new_right_proc =
3248  root_left_processor_plus_one[new_right_proc-1][irs];
3249  // Also get the right_proc_of_new_right_proc (in case
3250  // that it be necessary to invert the segment)
3251  const unsigned right_proc_of_new_right_proc =
3252  root_right_processor_plus_one[new_right_proc-1][irs];
3253  // Check the not inverted case (to the right and not
3254  // inverted)
3255  if (left_proc_of_new_right_proc != 0 &&
3256  left_proc_of_new_right_proc-1 == right_proc)
3257  {
3258  // Get the haloed element id of the current segment in the
3259  // new right processor and compare it to the halo element
3260  // id of the right_processor
3261  const unsigned left_halo_id =
3262  root_left_halo_element[new_right_proc-1][irs];
3263  const unsigned left_haloed_id =
3264  root_left_haloed_element[new_right_proc-1][irs];
3265 
3266  if (right_halo_id == left_haloed_id &&
3267  right_haloed_id == left_halo_id)
3268  {
3269  // We have a match of the segments (store the segment
3270  // number plus one on the processor to the right)
3271  right_connected_segment_plus_one[right_proc][right_seg]=
3272  irs+1;
3273  // Add the connectivity information to the list
3274  proc_seg_connectivity.push_back(candidate_seg);
3275  added_segment_to_the_right = true;
3276  break;
3277  }
3278  } // if (left_proc_of_new_right_proc-1 == right_proc)
3279 
3280  // Check the inverted case (to the right and inverted)
3281  if (right_proc_of_new_right_proc != 0 &&
3282  right_proc_of_new_right_proc-1 == right_proc)
3283  {
3284  // Get the haloed element id of the current segment
3285  // (inverted version) in the new right processor and
3286  // compare it to the halo element id of the
3287  // right_processor
3288  const unsigned inv_right_halo_id =
3289  root_right_halo_element[new_right_proc-1][irs];
3290  const unsigned inv_right_haloed_id =
3291  root_right_haloed_element[new_right_proc-1][irs];
3292  if (right_halo_id == inv_right_haloed_id &&
3293  right_haloed_id == inv_right_halo_id)
3294  {
3295  // We have a match of the segments (store the segment
3296  // number plus one on the processor to the right)
3297  right_connected_segment_plus_one[right_proc][right_seg]=
3298  irs+1;
3299  // Add the connectivity information to the list
3300  proc_seg_connectivity.push_back(candidate_seg);
3301  // In addition to the connectivity we need to invert the
3302  // segment
3303  const unsigned tmp_proc =
3304  root_left_processor_plus_one[new_right_proc-1][irs];
3305  const unsigned tmp_halo =
3306  root_left_halo_element[new_right_proc-1][irs];
3307  const unsigned tmp_haloed =
3308  root_left_haloed_element[new_right_proc-1][irs];
3309 
3310  root_left_processor_plus_one[new_right_proc-1][irs] =
3311  root_right_processor_plus_one[new_right_proc-1][irs];
3312  root_left_halo_element[new_right_proc-1][irs] =
3313  root_right_halo_element[new_right_proc-1][irs];
3314  root_left_haloed_element[new_right_proc-1][irs] =
3315  root_right_haloed_element[new_right_proc-1][irs];
3316 
3317  root_right_processor_plus_one[new_right_proc-1][irs] =
3318  tmp_proc;
3319  root_right_halo_element[new_right_proc-1][irs]=tmp_halo;
3320  root_right_haloed_element[new_right_proc-1][irs] =
3321  tmp_haloed;
3322 
3323  // ... and mark the segment as inverted in the root
3324  // processor to inform back to the owner processor
3325  root_segment_inverted[new_right_proc-1][irs] = 1;
3326 
3327  added_segment_to_the_right = true;
3328  break;
3329  }
3330  } // if (right_proc_of_new_right_proc-1 == right_proc)
3331  } // if (!done_segment[candidate_segment])
3332  } // for (irs < nsegs_new_left_proc)
3333 
3334 #ifdef PARANOID
3335  if (!added_segment_to_the_right)
3336  {
3337  std::ostringstream error_message;
3338  error_message
3339  << "The corresponding processor and segment to the right of "
3340  << "the current right\nmost segment was not found\n";
3341  throw OomphLibError(error_message.str(),
3342  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
3343  OOMPH_EXCEPTION_LOCATION);
3344  }
3345 #endif
3346  } // if (new_right_proc != 0)
3347  else
3348  {
3349  // No more segments to the left
3350  added_segment_to_the_right = false;
3351  }
3352 
3353  }while(added_segment_to_the_left || added_segment_to_the_right);
3354 
3355  // Once we have connected the segments then we can compute the
3356  // initial and final zeta values based on the arclength of each
3357  // individual segment
3358 
3359  // Get the total number of segments, which MUST be the same as the
3360  // total number of segments in all processors
3361  const unsigned ntotal_segments = proc_seg_connectivity.size();
3362 #ifdef PARANOID
3363  unsigned tmp_total_segments = 0;
3364  for (unsigned ip =0; ip < nproc; ip++)
3365  {
3366  tmp_total_segments+= root_nsegments_per_processor[ip];
3367  }
3368 
3369  // Check that the total number of segments in all processors is
3370  // the same as the number of segments that form the boundary
3371  if (ntotal_segments!=tmp_total_segments)
3372  {
3373  std::ostringstream error_message;
3374  error_message
3375  << "The number of sorted segments (" << ntotal_segments << ") on "
3376  << "boundary ("<< b <<")\nis different from the total number of "
3377  <<"segments ("<< tmp_total_segments <<") in all\nprocessors.\n\n";
3378  throw OomphLibError(error_message.str(),
3379  OOMPH_CURRENT_FUNCTION,
3380  OOMPH_EXCEPTION_LOCATION);
3381  } // if (ntotal_segments!=tmp_total_segments)
3382 #endif
3383 
3384  // Now that we know the connectivity of the segments we can
3385  // compute the initial arclength of each segment in the
3386  // processors. Additionally we also get the number of vertices
3387  // before each of the segments. Resize the containers considering
3388  // the number of segments in each processor
3389  for (unsigned ip = 0; ip < nproc; ip++)
3390  {
3391  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3392  root_initial_segment_arclength[ip].resize(nsegs_iproc);
3393  root_nvertices_before_segment[ip].resize(nsegs_iproc);
3394  }
3395 
3396  Vector<double> aux_initial_segment_arclength(ntotal_segments);
3397  Vector<unsigned> aux_nvertices_before_segment(ntotal_segments);
3398 
3399  ucounter = 0;
3400  for (std::list<std::pair<unsigned, unsigned> >::iterator
3401  it_list = proc_seg_connectivity.begin();
3402  it_list != proc_seg_connectivity.end(); it_list++)
3403  {
3404  const unsigned iproc = static_cast<unsigned>((*it_list).first);
3405  const unsigned iseg = static_cast<unsigned>((*it_list).second);
3406  const double iseg_arclength = root_segment_arclength[iproc][iseg];
3407  const unsigned iseg_nvertices = root_nvertices_per_segment[iproc][iseg];
3408 
3409  aux_initial_segment_arclength[ucounter] = root_accumulated_arclength;
3410  aux_nvertices_before_segment[ucounter] =
3411  root_accumulated_vertices_before_segment;
3412 
3413  // Set the initial zeta value for the segment
3414  root_initial_segment_arclength[iproc][iseg] = root_accumulated_arclength;
3415  // Set the number of vertices before the current segment
3416  root_nvertices_before_segment[iproc][iseg] =
3417  root_accumulated_vertices_before_segment;
3418 
3419  // Add the arclength of the segment to the global arclength
3420  root_accumulated_arclength+= iseg_arclength;
3421  // Add the number of vertices to the global number of vertices
3422  root_accumulated_vertices_before_segment+= iseg_nvertices - 1;
3423 
3424  // Increase the counter
3425  ucounter++;
3426  } // for (loop over the sorted segments to assigne initial
3427  // arlength and initial number of vertices)
3428 
3429  // Increase by one to get the total number of vertices on the
3430  // boundary
3431  root_accumulated_vertices_before_segment++;
3432 
3433  // Get the processors with the initial and final segment.
3434  proc_with_initial_seg = proc_seg_connectivity.front().first;
3435  proc_with_final_seg = proc_seg_connectivity.back().first;
3436  // Also get the corresponding initial and final segment indexes
3437  // (on the initial and final processors)
3438  initial_segment = proc_seg_connectivity.front().second;
3439  final_segment = proc_seg_connectivity.back().second;
3440 
3441  } // if (my_rank == root_processor)
3442 
3443  // Get the total number of segments
3444  unsigned root_ntotal_segments = 0;
3445  for (unsigned ip =0; ip < nproc; ip++)
3446  {
3447  root_ntotal_segments+= root_nsegments_per_processor[ip];
3448  }
3449 
3450  // Package the info. that will be sent to each processor. For the
3451  // unsigned package we send the number of vertices before each
3452  // segment in each processor and whether it was inverted or not
3453  // Package size
3454  const unsigned rspu = 2;
3455  flat_packed_unsigned_send_data.clear();
3456  flat_packed_unsigned_send_data.resize(root_ntotal_segments*rspu);
3457  unsigned ucounter = 0;
3458  // Collect the info. from all the segments in the processors
3459  for (unsigned ip = 0; ip < nproc; ip++)
3460  {
3461  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3462  for (unsigned is = 0; is < nsegs_iproc; is++)
3463  {
3464  flat_packed_unsigned_send_data[ucounter++] =
3465  root_nvertices_before_segment[ip][is];
3466  flat_packed_unsigned_send_data[ucounter++] =
3467  root_segment_inverted[ip][is];
3468  } // for (is < nsegs_iproc)
3469  } // for (ip < nproc)
3470 
3471  // How many data does the root processor will send to each processor
3472  Vector<int> root_nudata_to_send(nproc,0);
3473  for (unsigned ip =0; ip < nproc; ip++)
3474  {
3475  // Get the number of data to send to ip processor
3476  root_nudata_to_send[ip] = root_nsegments_per_processor[ip] * rspu;
3477  }
3478 
3479  // Store and compute the offsets for the data sent to each processor
3480  Vector<int> root_uoffsets_send(nproc,0);
3481  root_uoffsets_send[0] = 0;
3482  for (unsigned ip = 1; ip < nproc; ip++)
3483  {
3484  // Compute the offset to send the values to each processor
3485  root_uoffsets_send[ip] =
3486  root_uoffsets_send[ip-1] + root_nudata_to_send[ip-1];
3487  }
3488 
3489  // Number of data to receive from root
3490  unsigned nutotal_data_receive = nsegments * rspu;
3491 
3492  if (my_rank!=root_processor)
3493  {
3494  // Create at least one entry so we don't get a seg fault below
3495  if (flat_packed_unsigned_send_data.size()==0)
3496  {
3497  flat_packed_unsigned_send_data.resize(1);
3498  }
3499  }
3500 
3501  // Clear and resize the vector where to receive the info.
3502  flat_packed_unsigned_receive_data.clear();
3503  flat_packed_unsigned_receive_data.resize(nutotal_data_receive);
3504  // Create at least one entry so we don't get a seg fault below
3505  if (flat_packed_unsigned_receive_data.size()==0)
3506  {
3507  flat_packed_unsigned_receive_data.resize(1);
3508  }
3509 
3510  MPI_Scatterv(&flat_packed_unsigned_send_data[0],
3511  &root_nudata_to_send[0],
3512  &root_uoffsets_send[0],
3513  MPI_UNSIGNED,
3514  &flat_packed_unsigned_receive_data[0],
3515  nutotal_data_receive,
3516  MPI_UNSIGNED,
3517  root_processor,
3518  comm_pt->mpi_comm());
3519 
3520  // Package the info. that will be sent to each processor, for the
3521  // double package we send (one data per segment) the initial
3522  // arclength for each segment
3523  const unsigned rspd = 1;
3524  flat_packed_double_send_data.clear();
3525  flat_packed_double_send_data.resize(root_ntotal_segments*rspd);
3526  unsigned dcounter = 0;
3527  // Collect the info. from all the segments in the processors
3528  for (unsigned ip = 0; ip < nproc; ip++)
3529  {
3530  const unsigned nsegs_iproc = root_nsegments_per_processor[ip];
3531  for (unsigned is = 0; is < nsegs_iproc; is++)
3532  {
3533  flat_packed_double_send_data[dcounter++] =
3534  root_initial_segment_arclength[ip][is];
3535  }
3536  }
3537 
3538  // How many data does the root processor will send to each processor
3539  Vector<int> root_nddata_to_send(nproc,0);
3540  for (unsigned ip =0; ip < nproc; ip++)
3541  {
3542  // Number of data send to ip processor
3543  root_nddata_to_send[ip] = root_nsegments_per_processor[ip] * rspd;
3544  }
3545 
3546  // Store and compute the offsets for the data sent to each processor
3547  Vector<int> root_doffsets_send(nproc,0);
3548  root_doffsets_send[0] = 0;
3549  for (unsigned ip = 1; ip < nproc; ip++)
3550  {
3551  // Compute the offset to send the values to each processor
3552  root_doffsets_send[ip] =
3553  root_doffsets_send[ip-1] + root_nddata_to_send[ip-1];
3554  }
3555 
3556  // Number of double data to receive from root
3557  unsigned ndtotal_data_receive = nsegments * rspd;
3558 
3559  if (my_rank!=root_processor)
3560  {
3561  // Create at least one entry so we don't get a seg fault below
3562  if (flat_packed_double_send_data.size()==0)
3563  {
3564  flat_packed_double_send_data.resize(1);
3565  }
3566  }
3567 
3568  // Clear and resize the vector where to receive the info.
3569  flat_packed_double_receive_data.clear();
3570  flat_packed_double_receive_data.resize(ndtotal_data_receive);
3571  // Create at least one entry so we don't get a seg fault below
3572  if (flat_packed_double_receive_data.size()==0)
3573  {
3574  flat_packed_double_receive_data.resize(1);
3575  }
3576 
3577  MPI_Scatterv(&flat_packed_double_send_data[0],
3578  &root_nddata_to_send[0],
3579  &root_doffsets_send[0],
3580  MPI_DOUBLE,
3581  &flat_packed_double_receive_data[0],
3582  ndtotal_data_receive,
3583  MPI_DOUBLE,
3584  root_processor,
3585  comm_pt->mpi_comm());
3586 
3587  // Read if the segments need to be inverted and read the initial
3588  // arclengths
3589  ucounter = 0;
3590  dcounter = 0;
3591 
3592  // Read the info. from the flat package and store it in their
3593  // corresponding containers
3594  for (unsigned is = 0; is < nsegments; is++)
3595  {
3596  // The flat unsigned package
3597  nvertices_before_segment[is] =
3598  flat_packed_unsigned_receive_data[ucounter++];
3599  // The segment inverted flag
3600  segment_inverted[is] = flat_packed_unsigned_receive_data[ucounter++];
3601  // The flat double package
3602  initial_segment_arclength[is] =
3603  flat_packed_double_receive_data[dcounter++];
3604  } // for (is < nsegments)
3605 
3606  // Perform two additional communications to get the total number of
3607  // vertices, the processors with the initial and final segments, the
3608  // corresponding initial and final segments ...
3609  const unsigned numore_info = 5;
3610  Vector<unsigned> flat_package_unsigned_more_info(numore_info);
3611  // Prepare the info ...
3612  flat_package_unsigned_more_info[0] = root_accumulated_vertices_before_segment;
3613  flat_package_unsigned_more_info[1] = proc_with_initial_seg;
3614  flat_package_unsigned_more_info[2] = proc_with_final_seg;
3615  flat_package_unsigned_more_info[3] = initial_segment;
3616  flat_package_unsigned_more_info[4] = final_segment;
3617 
3618  // Send the info. to all processors
3619  MPI_Bcast(&flat_package_unsigned_more_info[0], numore_info,
3620  MPI_UNSIGNED, root_processor, comm_pt->mpi_comm());
3621 
3622  // ... and store the info. in the proper containers
3623  root_accumulated_vertices_before_segment = flat_package_unsigned_more_info[0];
3624  proc_with_initial_seg = flat_package_unsigned_more_info[1];
3625  proc_with_final_seg = flat_package_unsigned_more_info[2];
3626  initial_segment = flat_package_unsigned_more_info[3];
3627  final_segment = flat_package_unsigned_more_info[4];
3628 
3629  // Do the same for the maximum zeta value
3630  MPI_Bcast(&root_accumulated_arclength, 1, MPI_DOUBLE,
3631  root_processor, comm_pt->mpi_comm());
3632 
3633  // -----------------------------------------------------------------
3634  // Clear the storage to store the data that will be used by the
3635  // setup boundary coordinates method, if we do not perform the
3636  // cleaning then previous data from previous iterations will remain
3637  // there
3638  // -----------------------------------------------------------------
3639  // The info. for the boundary
3640  Boundary_initial_coordinate[b].clear();
3641  Boundary_final_coordinate[b].clear();
3642 
3643  Boundary_initial_zeta_coordinate[b].clear();
3644  Boundary_final_zeta_coordinate[b].clear();
3645 
3646  // The info. for the segments
3647  Boundary_segment_inverted[b].clear();
3648  Boundary_segment_initial_coordinate[b].clear();
3649  Boundary_segment_final_coordinate[b].clear();
3650 
3651  Boundary_segment_initial_zeta[b].clear();
3652  Boundary_segment_final_zeta[b].clear();
3653 
3654  Boundary_segment_initial_arclength[b].clear();
3655  Boundary_segment_final_arclength[b].clear();
3656 
3657  // Now copy all the info. to the containers to be sent to any other
3658  // mesh (in the adaptation method)
3659  for (unsigned is = 0; is < nsegments; is++)
3660  {
3661  // At this point we can get the initial and final coordinates for
3662  // each segment
3663  Vector<double> first_seg_coord(2);
3664  Vector<double> last_seg_coord(2);
3665 
3666  // In order to get the first and last coordinates of each segment we
3667  // first need to identify the first and last nonhalo element of each
3668  // segment, and then get the first and last node of the segment
3669 
3670  // Get the first nonhalo face element on the segment
3671  FiniteElement* first_seg_ele_pt =
3672  segment_sorted_nonhalo_ele_pt[is].front();
3673 
3674 #ifdef PARANOID
3675  // Check if the face element is nonhalo, it shouldn't, but better
3676  // check
3677  if (first_seg_ele_pt->is_halo())
3678  {
3679  std::ostringstream error_message;
3680  error_message
3681  << "The first face element in the (" << is << ")-th segment is halo\n";
3682  throw OomphLibError(error_message.str(),
3683  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
3684  OOMPH_EXCEPTION_LOCATION);
3685  } // if (tmp_first_bulk_ele_pt->is_halo())
3686 #endif
3687 
3688  // Number of nodes
3689  const unsigned nnod = first_seg_ele_pt->nnode();
3690 
3691  // Get the first node of the current segment
3692  Node *first_seg_node_pt = first_seg_ele_pt->node_pt(0);
3693  if (is_inverted[first_seg_ele_pt])
3694  {
3695  first_seg_node_pt = first_seg_ele_pt->node_pt(nnod-1);
3696  }
3697 
3698  // Get the last nonhalo face element on the segment
3699  FiniteElement* last_seg_ele_pt =
3700  segment_sorted_nonhalo_ele_pt[is].back();
3701 
3702 #ifdef PARANOID
3703  // Check if the face element is nonhalo, it shouldn't, but better
3704  // check
3705  if (last_seg_ele_pt->is_halo())
3706  {
3707  std::ostringstream error_message;
3708  error_message
3709  << "The last face element in the (" << is << ")-th segment is halo\n";
3710  throw OomphLibError(error_message.str(),
3711  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
3712  OOMPH_EXCEPTION_LOCATION);
3713  } // if (tmp_first_bulk_ele_pt->is_halo())
3714 #endif
3715 
3716  // Get the last node of the current segment
3717  Node *last_seg_node_pt = last_seg_ele_pt->node_pt(nnod-1);
3718  if (is_inverted[last_seg_ele_pt])
3719  {
3720  last_seg_node_pt = last_seg_ele_pt->node_pt(0);
3721  }
3722 
3723  // Get the coordinates for the first and last segment's node
3724  for (unsigned i = 0; i < 2; i++)
3725  {
3726  first_seg_coord[i] = first_seg_node_pt->x(i);
3727  last_seg_coord[i] = last_seg_node_pt->x(i);
3728  }
3729 
3730  // -----------------------------------------------------------------
3731  // Copy the info. if the segment is inverted
3732  Boundary_segment_inverted[b].push_back(segment_inverted[is]);
3733 
3734  // Check if the segment is inverted, if that is the case then invert
3735  // the first and last seg. coordinates
3736  if (!segment_inverted[is])
3737  {
3738  // Store the initial and final coordinates that will help to
3739  // identify the segments in the new meshes created from this one
3740  Boundary_segment_initial_coordinate[b].push_back(first_seg_coord);
3741  Boundary_segment_final_coordinate[b].push_back(last_seg_coord);
3742  }
3743  else
3744  {
3745  // Store the initial and final coordinates that will help to
3746  // identify the segments in the new meshes created from this one
3747  // Invert the initial and final coordinates
3748  Boundary_segment_initial_coordinate[b].push_back(last_seg_coord);
3749  Boundary_segment_final_coordinate[b].push_back(first_seg_coord);
3750  }
3751 
3752  // Now assign initial and final zeta boundary coordinates for each
3753  // segment
3754  // -----------------------------------------------------------------
3755  // If there is a geom object then
3756  if (boundary_geom_object_pt(b)!=0)
3757  {
3758  // Store the initial and final zeta for the current segments (we
3759  // got this when we assigned arclength to the segments in the
3760  // current processor)
3761  if (segment_inverted[is])
3762  {
3763  Boundary_segment_initial_zeta[b].push_back(final_zeta_segment[is]);
3764  Boundary_segment_final_zeta[b].push_back(initial_zeta_segment[is]);
3765  }
3766  else
3767  {
3768  Boundary_segment_initial_zeta[b].push_back(initial_zeta_segment[is]);
3769  Boundary_segment_final_zeta[b].push_back(final_zeta_segment[is]);
3770  }
3771  } // if (boundary_geom_object_pt(b)!=0)
3772  else
3773  {
3774  // Store the initial arclength and vertices number for the
3775  // current segment
3776  Boundary_segment_initial_arclength[b].push_back(
3777  initial_segment_arclength[is]);
3778 
3779  Boundary_segment_final_arclength[b].push_back(
3780  initial_segment_arclength[is] + segment_arclength[is]);
3781 
3782  } // else if (boundary_geom_object_pt(b)!=0)
3783 
3784  } // // for (is < nsegments)
3785 
3786  // Get the number of segments from the sets of nodes
3787 #ifdef PARANOID
3788  if (segment_all_nodes_pt.size() != nsegments)
3789  {
3790  std::ostringstream error_message;
3791  error_message
3792  <<"The number of segments ("<<nsegments<<") and the number of "
3793  <<"set of nodes ("<<segment_all_nodes_pt.size()<<") representing\n"
3794  <<"the\nsegments is different!!!\n\n";
3795  throw OomphLibError(error_message.str(),
3796  "TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values()",
3797  OOMPH_EXCEPTION_LOCATION);
3798  }
3799 #endif
3800 
3801  // The nodes have been assigned arc-length coordinates from one end
3802  // or the other of the connected segment.
3803 
3804  // -----------------------------------------------------------------
3805  // If mesh is distributed get the info. regarding the initial and
3806  // final nodes coordinates on the boundary, same as the zeta
3807  // boundary values for those nodes
3808 
3809  // Storage for the coordinates of the first and last nodes on the
3810  // boundary
3811  Vector<double> first_coordinate(2);
3812  Vector<double> last_coordinate(2);
3813 
3814  // Storage for the zeta coordinate of the first and last nodes on
3815  // the boundary
3816  Vector<double> first_node_zeta_coordinate(1,0.0);
3817  Vector<double> last_node_zeta_coordinate(1,0.0);
3818 
3819  // Send three data to all processors, the x[0], x[1] coordinate and
3820  // the zeta coordinate
3821  const unsigned ndtotal_data = 3;
3822  Vector<double> flat_packed_double_data_initial_seg(ndtotal_data);
3823 
3824  // If the mesh is distributed then check if this processor has the
3825  // initial segment
3826  if (my_rank == proc_with_initial_seg)
3827  {
3828  // Stores the firts element of the segment
3829  FiniteElement* first_ele_pt = 0;
3830  // Stores the first node of the boundary
3831  Node *first_node_pt = 0;
3832  // Check if the segment is inverted
3833  if (!segment_inverted[initial_segment])
3834  {
3835  // Get access to the first element on the segment marked as
3836  // initial
3837  first_ele_pt = segment_sorted_ele_pt[initial_segment].front();
3838 
3839  // Number of nodes
3840  const unsigned nnod = first_ele_pt->nnode();
3841 
3842  // Get the first node of the current segment
3843  first_node_pt = first_ele_pt->node_pt(0);
3844  if (is_inverted[first_ele_pt])
3845  {
3846  first_node_pt = first_ele_pt->node_pt(nnod-1);
3847  }
3848  } // if (!segment_inverted[initial_segment])
3849  else
3850  {
3851  // Get access to the first element on the segment marked as
3852  // initial
3853  first_ele_pt = segment_sorted_ele_pt[initial_segment].back();
3854 
3855  // Number of nodes
3856  const unsigned nnod = first_ele_pt->nnode();
3857 
3858  // Get the first node of the current segment
3859  first_node_pt = first_ele_pt->node_pt(nnod-1);
3860  if (is_inverted[first_ele_pt])
3861  {
3862  first_node_pt = first_ele_pt->node_pt(0);
3863  }
3864  } // else if (!segment_inverted[initial_segment])
3865 
3866  // Get the coordinates for the first node
3867  for (unsigned i = 0; i < 2; i++)
3868  {
3869  flat_packed_double_data_initial_seg[i] = first_node_pt->x(i);
3870  }
3871 
3872  // Get the zeta coordinates for the first node
3873  Vector<double> tmp_zeta(1);
3874  first_node_pt->get_coordinates_on_boundary(b, tmp_zeta);
3875 
3876  // If there is a geometric object associated to the boundary then
3877  // further process is necessary
3878  if (this->boundary_geom_object_pt(b)!=0)
3879  {
3880  //tmp_zeta[0] = this->boundary_coordinate_limits(b)[0];
3881  }
3882  else
3883  {
3884  // Check if the initial boundary coordinate is different from
3885  // zero, if that is the case then we need to set it to zero
3886  if (tmp_zeta[0] >= 1.0e-14)
3887  {
3888  tmp_zeta[0]=0;
3889  }
3890  } // if (this->boundary_geom_object_pt(b)!=0)
3891 
3892  // Store the initial zeta value
3893  flat_packed_double_data_initial_seg[2] = tmp_zeta[0];
3894 
3895  } // if (my_rank == proc_with_initial_seg)
3896 
3897  // All processor receive the info. from the processor that has the
3898  // initial segment
3899  MPI_Bcast(&flat_packed_double_data_initial_seg[0], ndtotal_data,
3900  MPI_DOUBLE, proc_with_initial_seg, comm_pt->mpi_comm());
3901 
3902  // ... and all processor put that info. into the appropriate
3903  // storages
3904  for (unsigned i = 0; i < 2; i++)
3905  {
3906  first_coordinate[i] = flat_packed_double_data_initial_seg[i];
3907  }
3908  first_node_zeta_coordinate[0]=flat_packed_double_data_initial_seg[2];
3909 
3910  // -----------------------------------------------------------------
3911  // Send three data to all processors, the x[0], x[1] coordinate and
3912  // the zeta coordinate
3913  Vector<double> flat_packed_double_data_final_seg(ndtotal_data);
3914 
3915  // If the mesh is distributed then check if this processor has the
3916  // final segment
3917  if (my_rank == proc_with_final_seg)
3918  {
3919  // Get access to the last element on the segment
3920  FiniteElement* last_ele_pt = 0;
3921 
3922  // Get the last node of the current segment
3923  Node *last_node_pt = 0;
3924 
3925  // Check if the segment is inverted
3926  if (!segment_inverted[final_segment])
3927  {
3928  // Get access to the last element on the segment marked as
3929  // final
3930  last_ele_pt = segment_sorted_ele_pt[final_segment].back();
3931 
3932  // Number of nodes
3933  const unsigned nnod = last_ele_pt->nnode();
3934 
3935  // Get the last node of the current segment
3936  last_node_pt = last_ele_pt->node_pt(nnod-1);
3937  if (is_inverted[last_ele_pt])
3938  {
3939  last_node_pt = last_ele_pt->node_pt(0);
3940  }
3941  } // if (!segment_inverted[final_segment])
3942  else
3943  {
3944  // Get access to the first element on the segment marked as
3945  // initial
3946  last_ele_pt = segment_sorted_ele_pt[final_segment].front();
3947 
3948  // Number of nodes
3949  const unsigned nnod = last_ele_pt->nnode();
3950 
3951  // Get the first node of the current segment
3952  last_node_pt = last_ele_pt->node_pt(0);
3953  if (is_inverted[last_ele_pt])
3954  {
3955  last_node_pt = last_ele_pt->node_pt(nnod-1);
3956  }
3957  } // if (!segment_inverted[final_segment])
3958 
3959  // Get the coordinates for the last node
3960  for (unsigned i = 0; i < 2; i++)
3961  {
3962  flat_packed_double_data_final_seg[i]=last_node_pt->x(i);
3963  }
3964 
3965  // Get the zeta coordinates for the last node
3966  Vector<double> tmp_zeta(1);
3967  last_node_pt->get_coordinates_on_boundary(b, tmp_zeta);
3968 
3969  // If there is not a geometric object associated to the boundary
3970  // then further process is required
3971  if (this->boundary_geom_object_pt(b)!=0)
3972  {
3973  // Do nothing
3974  } // if (this->boundary_geom_object_pt(b)!=0)
3975  else
3976  {
3977  // Check if the final boundary coordinate is different from
3978  // the boundary arclength, if that is the case then we need
3979  // to set it to the accumulated arclength
3980  if (std::fabs(tmp_zeta[0] - root_accumulated_arclength) >= 1.0e-14)
3981  {
3982  tmp_zeta[0] = root_accumulated_arclength;
3983  }
3984  } // else if (this->boundary_geom_object_pt(b)!=0)
3985 
3986  // Store the final zeta value
3987  flat_packed_double_data_final_seg[2] = tmp_zeta[0];
3988 
3989  } // if (my_rank == proc_with_final_seg)
3990 
3991  // All processor receive the info. from the processor that has the
3992  // final segment
3993  MPI_Bcast(&flat_packed_double_data_final_seg[0], ndtotal_data,
3994  MPI_DOUBLE, proc_with_final_seg, comm_pt->mpi_comm());
3995 
3996  // All processor receive the info. from the processor that has the
3997  // final segment
3998  for (unsigned i = 0; i < 2; i++)
3999  {
4000  last_coordinate[i] = flat_packed_double_data_final_seg[i];
4001  }
4002  last_node_zeta_coordinate[0]=flat_packed_double_data_final_seg[2];
4003 
4004  // -----------------------------------------------------------------
4005  // Copy the values to the permanent storage
4006  Boundary_initial_coordinate[b] = first_coordinate;
4007  Boundary_final_coordinate[b] = last_coordinate;
4008 
4009  Boundary_initial_zeta_coordinate[b] = first_node_zeta_coordinate;
4010  Boundary_final_zeta_coordinate[b] = last_node_zeta_coordinate;
4011 
4012  // If we are dealing with an internal boundary then re-assign the
4013  // initial and final zeta values for the segments
4014  if (is_internal_boundary)
4015  {
4016  // Only re-assign zeta values if there are at least one nonhalo
4017  // segment, if all the possible segments are halo then the
4018  // synchronisation method will be in charge of assigning the
4019  // correct boundary coordinates
4020  if (nsegments > 0)
4021  {
4022  // Call the following method to re-construct the segments but
4023  // using only the nonhalo elements, therefore the boundary
4024  // coordinates need to be re-assigned
4025  re_assign_initial_zeta_values_for_internal_boundary(
4026  b, segment_sorted_nonhalo_ele_pt, is_inverted);
4027  }
4028 
4029  } // if (is_internal_boundary)
4030 
4031  // Now identify the boundary segments
4032  if (nsegments > 0)
4033  {
4034  // Identify the boundary segments in the current mesh
4035  //identify_boundary_segments_and_assign_initial_zeta_values(
4036  // b, all_face_ele_pt, is_internal_boundary, face_to_bulk_element_pt);
4037  identify_boundary_segments_and_assign_initial_zeta_values(b,this);
4038  } // if (nsegments > 0)
4039 
4040  // Clean all the created face elements
4041  for (unsigned i = 0; i < n_all_face_ele; i++)
4042  {
4043  delete all_face_ele_pt[i];
4044  all_face_ele_pt[i] = 0;
4045  }
4046 
4047  }
4048 
4049  //======================================================================
4050  /// \short Re-assign the boundary segments initial zeta (arclength)
4051  /// for those internal boundaries that were splited during the
4052  /// distribution process. Those boundaries that have one face element
4053  /// at each side of the boundary. Here we create the segments only
4054  /// with the nonhalo elements, therefore the boundary coordinates
4055  /// need to be re-assigned to be passed to the new meshes
4056  //======================================================================
4057  template<class ELEMENT>
4060  const unsigned& b,
4061  Vector<std::list<FiniteElement*> > &old_segment_sorted_ele_pt,
4062  std::map<FiniteElement*, bool> &old_is_inverted)
4063  {
4064  // ------------------------------------------------------------------
4065  // First: Get the face elements associated with the current boundary
4066  // Only include nonhalo face elements
4067  // ------------------------------------------------------------------
4068  // Temporary storage for face elements
4069  Vector<FiniteElement*> face_el_pt;
4070 
4071  // Temporary storage for the number of elements adjacent to the
4072  // boundary
4073  unsigned nele = 0;
4074 
4075  // Temporary storage for elements adjacent to the boundary that have
4076  // a common edge (related with internal boundaries)
4077  unsigned n_repeated_ele = 0;
4078 
4079  const unsigned n_regions = this->nregion();
4080 
4081  // Temporary storage for already done nodes
4082  Vector<std::pair<Node*, Node*> > done_nodes_pt;
4083 
4084  // If there is more than one region then only use boundary
4085  // coordinates from the bulk side (region 0)
4086  if (n_regions > 1)
4087  {
4088  for (unsigned rr = 0 ; rr < n_regions; rr++)
4089  {
4090  const unsigned region_id =
4091  static_cast<unsigned>(this->Region_attribute[rr]);
4092 
4093  // Loop over all elements on boundaries in region i_r
4094  const unsigned nel_in_region =
4095  this->nboundary_element_in_region(b, region_id);
4096 
4097  unsigned nel_repetead_in_region = 0;
4098 
4099  // Only bother to do anything else, if there are elements
4100  // associated with the boundary and the current region
4101  if (nel_in_region > 0)
4102  {
4103  bool repeated = false;
4104 
4105  // Loop over the bulk elements adjacent to boundary b
4106  for (unsigned e = 0; e < nel_in_region; e++)
4107  {
4108  // Get pointer to the bulk element that is adjacent to
4109  // boundary b
4110  FiniteElement* bulk_elem_pt =
4111  this->boundary_element_in_region_pt(b, region_id, e);
4112 
4113  // Remember only work with non halo elements
4114  if (bulk_elem_pt->is_halo())
4115  {
4116  n_repeated_ele++;
4117  continue;
4118  }
4119 
4120  // Find the index of the face of element e along boundary b
4121  int face_index =
4122  this->face_index_at_boundary_in_region(b,region_id,e);
4123 
4124  // Before adding the new element we need to be sure that the
4125  // edge that this element represent has not been already
4126  // added
4127  FiniteElement* tmp_ele_pt =
4128  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
4129 
4130  const unsigned n_nodes = tmp_ele_pt->nnode();
4131 
4132  std::pair<Node*, Node*> tmp_pair =
4133  std::make_pair(tmp_ele_pt->node_pt(0),
4134  tmp_ele_pt->node_pt(n_nodes - 1));
4135 
4136  std::pair<Node*, Node*> tmp_pair_inverse =
4137  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
4138  tmp_ele_pt->node_pt(0));
4139 
4140  // Search for repeated nodes
4141  const unsigned repeated_nodes_size = done_nodes_pt.size();
4142  for (unsigned l = 0; l < repeated_nodes_size; l++)
4143  {
4144  if (tmp_pair == done_nodes_pt[l] ||
4145  tmp_pair_inverse == done_nodes_pt[l])
4146  {
4147  nel_repetead_in_region++;
4148  repeated = true;
4149  break;
4150  }
4151  }
4152 
4153  // Create new face element
4154  if (!repeated)
4155  {
4156  // Add the pair of nodes (edge) to the node dones
4157  done_nodes_pt.push_back(tmp_pair);
4158  // Add the element to the face elements
4159  face_el_pt.push_back(tmp_ele_pt);
4160  }
4161  else
4162  {
4163  // Clean up
4164  delete tmp_ele_pt;
4165  tmp_ele_pt = 0;
4166  }
4167 
4168  // Re-start
4169  repeated = false;
4170 
4171  } // for nel
4172 
4173  nele += nel_in_region;
4174 
4175  n_repeated_ele += nel_repetead_in_region;
4176 
4177  } // if (nel_in_region > 0)
4178  } // for (rr < n_regions)
4179  } // if (n_regions > 1)
4180  //Otherwise it's just the normal boundary functions
4181  else
4182  {
4183  // Loop over all elements on boundaries
4184  nele = this->nboundary_element(b);
4185 
4186  //Only bother to do anything else, if there are elements
4187  if (nele > 0)
4188  {
4189  // Check for repeated ones
4190  bool repeated = false;
4191 
4192  // Loop over the bulk elements adjacent to boundary b
4193  for (unsigned e = 0; e < nele; e++)
4194  {
4195  // Get pointer to the bulk element that is adjacent to
4196  // boundary b
4197  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
4198 
4199  // Skip the halo elements, they are not included
4200  if (bulk_elem_pt->is_halo())
4201  {
4202  n_repeated_ele++;
4203  continue;
4204  }
4205 
4206  //Find the index of the face of element e along boundary b
4207  int face_index = this->face_index_at_boundary(b, e);
4208 
4209  // Before adding the new element we need to be sure that the
4210  // edge that this element represents has not been already
4211  // added (only applies for internal boundaries)
4212  FiniteElement* tmp_ele_pt =
4213  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
4214 
4215  const unsigned n_nodes = tmp_ele_pt->nnode();
4216 
4217  std::pair<Node*, Node*> tmp_pair =
4218  std::make_pair(tmp_ele_pt->node_pt(0),
4219  tmp_ele_pt->node_pt(n_nodes - 1));
4220 
4221  std::pair<Node*, Node*> tmp_pair_inverse =
4222  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
4223  tmp_ele_pt->node_pt(0));
4224 
4225  // Search for repeated nodes
4226  const unsigned repeated_nodes_size = done_nodes_pt.size();
4227  for (unsigned l = 0; l < repeated_nodes_size; l++)
4228  {
4229  if (tmp_pair == done_nodes_pt[l] ||
4230  tmp_pair_inverse == done_nodes_pt[l])
4231  {
4232  // Increase the number of repeated elements
4233  n_repeated_ele++;
4234  // Mark the element as repeated
4235  repeated = true;
4236  break;
4237  }
4238  }
4239 
4240  // Create new face element
4241  if (!repeated)
4242  {
4243  // Add the pair of nodes (edge) to the node dones
4244  done_nodes_pt.push_back(tmp_pair);
4245  // Add the element to the face elements
4246  face_el_pt.push_back(tmp_ele_pt);
4247  }
4248  else
4249  {
4250  // Free the repeated bulk element!!
4251  delete tmp_ele_pt;
4252  tmp_ele_pt = 0;
4253  }
4254 
4255  // Re-start
4256  repeated = false;
4257 
4258  } // for (e < nel)
4259  } // if (nel > 0)
4260 
4261  } // else (n_regions > 1)
4262 
4263  // Do not consider the repeated elements
4264  nele-= n_repeated_ele;
4265 
4266 #ifdef PARANOID
4267  if (nele!=face_el_pt.size())
4268  {
4269  std::ostringstream error_message;
4270  error_message
4271  << "The independet counting of face elements ("<<nele<<") for "
4272  << "boundary ("<<b<<") is different\n"
4273  << "from the real number of face elements in the container ("
4274  << face_el_pt.size() <<")\n";
4275  //<< "Possible memory leak\n"
4276  throw OomphLibError(error_message.str(),
4277  OOMPH_CURRENT_FUNCTION,
4278  OOMPH_EXCEPTION_LOCATION);
4279  }
4280 #endif
4281 
4282  // ----------------------------------------------------------------
4283  // Second: Sort the face elements, only consider nonhalo elements
4284  // ----------------------------------------------------------------
4285 
4286  // Get the total number of nonhalo face elements
4287  const unsigned nnon_halo_face_elements = face_el_pt.size();
4288 
4289  // The vector of list to store the "segments" that compound the
4290  // boundary (segments may appear only in a distributed mesh)
4291  Vector<std::list<FiniteElement*> > segment_sorted_ele_pt;
4292 
4293  // Number of already sorted face elements
4294  unsigned nsorted_face_elements = 0;
4295 
4296  // Keep track of who's done
4297  std::map<FiniteElement*, bool> done_el;
4298 
4299  // Keep track of which element is inverted
4300  std::map<FiniteElement*, bool> is_inverted;
4301 
4302  // Iterate until all possible segments have been created
4303  while(nsorted_face_elements < nnon_halo_face_elements)
4304  {
4305  // The ordered list of face elements (in a distributed mesh a
4306  // collection of contiguous face elements define a segment)
4307  std::list<FiniteElement*> sorted_el_pt;
4308 
4309 #ifdef PARANOID
4310  // Select an initial element for the segment
4311  bool found_initial_face_element = false;
4312 #endif
4313 
4314  FiniteElement* ele_face_pt = 0;
4315 
4316  unsigned iface = 0;
4317  for (iface = 0; iface < nele; iface++)
4318  {
4319  ele_face_pt = face_el_pt[iface];
4320  // If not done then take it as initial face element
4321  if (!done_el[ele_face_pt])
4322  {
4323 #ifdef PARANOID
4324  // Mark as found the root face element
4325  found_initial_face_element = true;
4326 #endif
4327  // Increase the number of sorted face elements
4328  nsorted_face_elements++;
4329  // Increase the counter to mark the position of the next
4330  // element number
4331  iface++;
4332  // Add the face element in the list of sorted face elements
4333  sorted_el_pt.push_back(ele_face_pt);
4334  // Mark as done
4335  done_el[ele_face_pt] = true;
4336  break;
4337  } // if (!done_el[ele_face_pt])
4338  } // for (iface < nele)
4339 
4340 #ifdef PARANOID
4341  if (!found_initial_face_element)
4342  {
4343  std::ostringstream error_message;
4344  error_message
4345  <<"Could not find an initial face element for the current segment\n";
4346  throw OomphLibError(error_message.str(),
4347  "TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary()",
4348  OOMPH_EXCEPTION_LOCATION);
4349  }
4350 #endif
4351 
4352  // Number of nodes
4353  const unsigned nnod = ele_face_pt->nnode();
4354 
4355  // Left and rightmost nodes (the left and right nodes of the
4356  // current face element)
4357  Node* left_node_pt = ele_face_pt->node_pt(0);
4358  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
4359 
4360  // Continue iterating if a new face element has been added to the
4361  // list
4362  bool face_element_added = false;
4363 
4364  // While a new face element has been added to the set of sorted
4365  // face elements then re-iterate
4366  do
4367  {
4368  // Start from the next face element since we have already added
4369  // the previous one as the initial face element (any previous
4370  // face element had to be added on previous iterations)
4371  for (unsigned iiface = iface; iiface < nele; iiface++)
4372  {
4373  // Re-start flag
4374  face_element_added = false;
4375 
4376  // Get the candidate element
4377  ele_face_pt = face_el_pt[iiface];
4378 
4379  // Check that the candidate element has not been done and is
4380  // not a halo element
4381  if (!(done_el[ele_face_pt]))
4382  {
4383  // Get the left and right nodes of the current element
4384  Node* local_left_node_pt = ele_face_pt->node_pt(0);
4385  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
4386 
4387  // New element fits at the left of segment and is not inverted
4388  if (left_node_pt == local_right_node_pt)
4389  {
4390  left_node_pt = local_left_node_pt;
4391  sorted_el_pt.push_front(ele_face_pt);
4392  is_inverted[ele_face_pt] = false;
4393  face_element_added = true;
4394  }
4395  // New element fits at the left of segment and is inverted
4396  else if (left_node_pt == local_left_node_pt)
4397  {
4398  left_node_pt = local_right_node_pt;
4399  sorted_el_pt.push_front(ele_face_pt);
4400  is_inverted[ele_face_pt] = true;
4401  face_element_added = true;
4402  }
4403  // New element fits on the right of segment and is not inverted
4404  else if (right_node_pt == local_left_node_pt)
4405  {
4406  right_node_pt = local_right_node_pt;
4407  sorted_el_pt.push_back(ele_face_pt);
4408  is_inverted[ele_face_pt] = false;
4409  face_element_added = true;
4410  }
4411  // New element fits on the right of segment and is inverted
4412  else if (right_node_pt == local_right_node_pt)
4413  {
4414  right_node_pt = local_left_node_pt;
4415  sorted_el_pt.push_back(ele_face_pt);
4416  is_inverted[ele_face_pt] = true;
4417  face_element_added = true;
4418  }
4419 
4420  if (face_element_added)
4421  {
4422  done_el[ele_face_pt] = true;
4423  nsorted_face_elements++;
4424  break;
4425  } // if (face_element_added)
4426 
4427  } // if (!(done_el[ele_face_pt]))
4428 
4429  } // for (iiface<nnon_halo_face_element)
4430 
4431  }while(face_element_added &&
4432  (nsorted_face_elements < nnon_halo_face_elements));
4433 
4434  // Store the created segment in the vector of segments
4435  segment_sorted_ele_pt.push_back(sorted_el_pt);
4436 
4437  } // while(nsorted_face_elements < nnon_halo_face_elements);
4438 
4439  // --------------------------------------------------------------
4440  // Third: We have the face elements sorted, now assign boundary
4441  // coordinates to the nodes in the segments and compute the
4442  // arclength of the segment.
4443  // --------------------------------------------------------------
4444 
4445  // The number of segments in this processor
4446  const unsigned nsegments = segment_sorted_ele_pt.size();
4447 
4448 #ifdef PARANOID
4449  if (nnon_halo_face_elements > 0 && nsegments == 0)
4450  {
4451  std::ostringstream error_message;
4452  error_message
4453  << "The number of segments is zero, but the number of nonhalo\n"
4454  << "elements is: (" << nnon_halo_face_elements << ")\n";
4455  throw OomphLibError(error_message.str(),
4456  OOMPH_CURRENT_FUNCTION,
4457  OOMPH_EXCEPTION_LOCATION);
4458  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
4459 #endif
4460 
4461  // Vector of sets that stores the nodes of each segment based on a
4462  // lexicographically order starting from the bottom left node of
4463  // each segment
4464  Vector<std::set<Node*> > segment_all_nodes_pt(nsegments);
4465 
4466  // Stores the nodes on each segment in the order they appear in the
4467  // face elements
4468  Vector<Vector<Node*> > sorted_segment_all_nodes_pt(nsegments);
4469 
4470  // Associate and arclength to each node on each segment of the
4471  // boundary, the nodes and therefore the arclength come in the same
4472  // order as the face elements
4473  Vector<Vector<double> > sorted_segment_node_arclength(nsegments);
4474 
4475  // The arclength of each segment in the current processor
4476  Vector<double> segment_arclength(nsegments);
4477 
4478  // The number of vertices of each segment
4479  Vector<unsigned> nvertices_per_segment(nsegments);
4480 
4481  // The initial zeta for the segment
4482  Vector<double> initial_zeta_segment(nsegments);
4483 
4484  // The final zeta for the segment
4485  Vector<double> final_zeta_segment(nsegments);
4486 
4487  // Go through all the segments and compute the LOCAL boundary
4488  // coordinates
4489  for (unsigned is = 0; is < nsegments; is++)
4490  {
4491 #ifdef PARANOID
4492  if (segment_sorted_ele_pt[is].size() == 0)
4493  {
4494  std::ostringstream error_message;
4495  error_message
4496  << "The (" << is << ")-th segment has no elements\n";
4497  throw OomphLibError(error_message.str(),
4498  "TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary()",
4499  OOMPH_EXCEPTION_LOCATION);
4500  } // if (segment_sorted_ele_pt[is].size() == 0)
4501 #endif
4502 
4503  // Get access to the first element on the segment
4504  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
4505 
4506  // Number of nodes
4507  const unsigned nnod = first_ele_pt->nnode();
4508 
4509  // Get the first node of the current segment
4510  Node *first_node_pt = first_ele_pt->node_pt(0);
4511  if (is_inverted[first_ele_pt])
4512  {
4513  first_node_pt = first_ele_pt->node_pt(nnod-1);
4514  }
4515 
4516  // Coordinates of left node
4517  double x_left = first_node_pt->x(0);
4518  double y_left = first_node_pt->x(1);
4519 
4520  // Initialise boundary coordinate (local boundary coordinate for
4521  // boundaries with more than one segment)
4522  Vector<double> zeta(1, 0.0);
4523 
4524  // If we have associated a GeomObject then it is not necessary
4525  // to compute the arclength, only read the values from the nodes at
4526  // the edges
4527  if (this->boundary_geom_object_pt(b)!=0)
4528  {
4529  first_node_pt->get_coordinates_on_boundary(b, zeta);
4530  initial_zeta_segment[is] = zeta[0];
4531 
4532  // Get access to the last element on the segment
4533  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
4534 
4535  // Get the last node of the current segment
4536  Node *last_node_pt = last_ele_pt->node_pt(nnod-1);
4537  if (is_inverted[last_ele_pt])
4538  {
4539  last_node_pt = last_ele_pt->node_pt(0);
4540  }
4541 
4542  last_node_pt->get_coordinates_on_boundary(b, zeta);
4543  final_zeta_segment[is] = zeta[0];
4544  }
4545 
4546  // Sort the nodes in the segment (lexicographically bottom left
4547  // node)
4548  std::set<Node*> local_nodes_pt;
4549  local_nodes_pt.insert(first_node_pt);
4550 
4551  // Associate and arclength to the sorted nodes
4552  Vector<double> sorted_node_arclength;
4553  sorted_node_arclength.push_back(0.0);
4554 
4555  // Sorts the nodes in the segments according their sorting in the
4556  // face elements
4557  Vector<Node*> sorted_nodes_pt;
4558  sorted_nodes_pt.push_back(first_node_pt);
4559 
4560  // Now loop over nodes in order
4561  for (std::list<FiniteElement*>::iterator it =
4562  segment_sorted_ele_pt[is].begin();
4563  it != segment_sorted_ele_pt[is].end(); it++)
4564  {
4565  // Get the face element
4566  FiniteElement* el_pt = *it;
4567 
4568  // Start node and increment
4569  unsigned k_nod = 1;
4570  int nod_diff = 1;
4571  if (is_inverted[el_pt])
4572  {
4573  k_nod = nnod - 2;
4574  nod_diff = -1;
4575  }
4576 
4577  // Loop over nodes
4578  for (unsigned j = 1; j < nnod; j++)
4579  {
4580  Node* nod_pt = el_pt->node_pt(k_nod);
4581  k_nod += nod_diff;
4582 
4583  // Coordinates of right node
4584  double x_right = nod_pt->x(0);
4585  double y_right = nod_pt->x(1);
4586 
4587  // Increment boundary coordinate
4588  zeta[0] += sqrt(
4589  (x_right - x_left) * (x_right - x_left) + (y_right - y_left)
4590  * (y_right - y_left));
4591 
4592  // When we have a GeomObject associated to the boundary we already
4593  // know the zeta values for the nodes, there is no need to compute
4594  // the arclength
4595  if (this->boundary_geom_object_pt(b)==0)
4596  {
4597  // Set boundary coordinate
4598 // nod_pt->set_coordinates_on_boundary(b, zeta);
4599  }
4600 
4601  // Increment reference coordinate
4602  x_left = x_right;
4603  y_left = y_right;
4604 
4605  // Get lexicographically bottom left node but only
4606  // use vertex nodes as candidates
4607  local_nodes_pt.insert(nod_pt);
4608 
4609  // Associate the arclength for the current node
4610  sorted_node_arclength.push_back(zeta[0]);
4611 
4612  // Store the node in the sorted nodes storage
4613  sorted_nodes_pt.push_back(nod_pt);
4614 
4615  } // for (j < nnod)
4616 
4617  } // iterator over the elements in the segment
4618 
4619  // Info. to be passed to the other processors
4620  // The initial arclength for the segment that goes after this depends
4621  // on the current segment arclength
4622  segment_arclength[is] = zeta[0];
4623 
4624  // Info. to be passed to the other processors
4625  // The initial vertex number for the segment that goes after this
4626  // depends on the current sement vertices number
4627  nvertices_per_segment[is] = local_nodes_pt.size();
4628 
4629  // Add the nodes for the corresponding segment in the container
4630  segment_all_nodes_pt[is] = local_nodes_pt;
4631 
4632  // Add the arclengths to the nodes in the segment
4633  sorted_segment_node_arclength[is] = sorted_node_arclength;
4634 
4635  // Add the sorted nodes to the storage
4636  sorted_segment_all_nodes_pt[is] = sorted_nodes_pt;
4637 
4638  // The attaching of the halo elements at both sides of the segments is
4639  // performed only if segments connectivity needs to be computed
4640 
4641  } // for (is < nsegments)
4642 
4643  // ------------------------------------------------------------------
4644  // Fourth: Now we have the segments sorted, with arclength and with
4645  // LOCAL boundary coordinates assigned to the nodes. Identify the
4646  // nodes on the segments with the input segments and re-assign all
4647  // the info. related with the identification of segments
4648  // ------------------------------------------------------------------
4649 
4650  // Get the number of segments for the old sorted segments
4651  const unsigned old_nsegments = old_segment_sorted_ele_pt.size();
4652 
4653  // ------------------------------------------------------------------
4654  // Copy the old info. in temporary storages
4655  Vector<unsigned> old_boundary_segment_inverted(old_nsegments);
4656 
4657  Vector<Vector<double> >
4658  old_boundary_segment_initial_coordinate(old_nsegments);
4659  Vector<Vector<double> >
4660  old_boundary_segment_final_coordinate(old_nsegments);
4661 
4662  Vector<double> old_boundary_segment_initial_zeta(old_nsegments);
4663  Vector<double> old_boundary_segment_final_zeta(old_nsegments);
4664 
4665  Vector<double> old_boundary_segment_initial_arclength(old_nsegments);
4666  Vector<double> old_boundary_segment_final_arclength(old_nsegments);
4667 
4668  // Back-up the information
4669  for (unsigned old_is = 0; old_is < old_nsegments; old_is++)
4670  {
4671  old_boundary_segment_inverted[old_is] =
4672  boundary_segment_inverted(b)[old_is];
4673 
4674  old_boundary_segment_initial_coordinate[old_is].resize(2);
4675  old_boundary_segment_final_coordinate[old_is].resize(2);
4676  for (unsigned i = 0; i < 2; i++)
4677  {
4678  old_boundary_segment_initial_coordinate[old_is][i] =
4679  boundary_segment_initial_coordinate(b)[old_is][i];
4680 
4681  old_boundary_segment_final_coordinate[old_is][i] =
4682  boundary_segment_final_coordinate(b)[old_is][i];
4683  }
4684 
4685  // Check if the boundary has an associated GeomObject
4686  if (this->boundary_geom_object_pt(b)!=0)
4687  {
4688  old_boundary_segment_initial_zeta[old_is] =
4689  boundary_segment_initial_zeta(b)[old_is];
4690 
4691  old_boundary_segment_final_zeta[old_is] =
4692  boundary_segment_final_zeta(b)[old_is];
4693 
4694  } // if (this->boundary_geom_object_pt(b)!=0)
4695  else
4696  {
4697  old_boundary_segment_initial_arclength[old_is] =
4698  boundary_segment_initial_arclength(b)[old_is];
4699 
4700  old_boundary_segment_final_arclength[old_is] =
4701  boundary_segment_final_arclength(b)[old_is];
4702 
4703  } // else if (this->boundary_geom_object_pt(b)!=0)
4704 
4705  } // for (old_is < old_nsegments)
4706 
4707  // ------------------------------------------------------------------
4708  // Now clear the original storages
4709  Boundary_segment_inverted[b].clear();
4710  Boundary_segment_initial_coordinate[b].clear();
4711  Boundary_segment_final_coordinate[b].clear();
4712 
4713  Boundary_segment_initial_zeta[b].clear();
4714  Boundary_segment_final_zeta[b].clear();
4715 
4716  Boundary_segment_initial_arclength[b].clear();
4717  Boundary_segment_final_arclength[b].clear();
4718  // ------------------------------------------------------------------
4719  // .. and resize the storages for the new number of segments
4720  Boundary_segment_inverted[b].resize(nsegments);
4721  Boundary_segment_initial_coordinate[b].resize(nsegments);
4722  Boundary_segment_final_coordinate[b].resize(nsegments);
4723 
4724  // Check if the boundary has an associated GeomObject
4725  if (this->boundary_geom_object_pt(b)!=0)
4726  {
4727  Boundary_segment_initial_zeta[b].resize(nsegments);
4728  Boundary_segment_final_zeta[b].resize(nsegments);
4729  }
4730  else
4731  {
4732  Boundary_segment_initial_arclength[b].resize(nsegments);
4733  Boundary_segment_final_arclength[b].resize(nsegments);
4734  }
4735  // ------------------------------------------------------------------
4736  // map to know if the new segment has been re-assigned the info.
4737  std::map<unsigned, bool> done_segment;
4738 
4739  // Count the number of re-assigned segments with the new values
4740  unsigned re_assigned_segments = 0;
4741 
4742  // Go through all the old segments (the input segments)
4743  for (unsigned old_is = 0; old_is < old_nsegments; old_is++)
4744  {
4745  // Get the first and last zeta values for the current segment
4746  const double old_initial_arclength =
4747  old_boundary_segment_initial_arclength[old_is];
4748  const double old_final_arclength =
4749  old_boundary_segment_final_arclength[old_is];
4750  // Get the "is inverted" segment information
4751  const unsigned old_inverted_segment =
4752  old_boundary_segment_inverted[old_is];
4753 
4754  // Check if the boundary coordinates in the segment go in
4755  // increasing or decreasing order
4756  bool old_increasing_order = false;
4757  if (old_initial_arclength < old_final_arclength)
4758  {old_increasing_order = true;}
4759 
4760  // Now get the first and last node of the current segment
4761  // Get the first element
4762  FiniteElement* first_old_seg_ele_pt =
4763  old_segment_sorted_ele_pt[old_is].front();
4764 
4765  // Number of nodes
4766  const unsigned nnod = first_old_seg_ele_pt->nnode();
4767 
4768  // Get the first node of the current segment
4769  Node *first_old_seg_node_pt = first_old_seg_ele_pt->node_pt(0);
4770  if (old_is_inverted[first_old_seg_ele_pt])
4771  {
4772  first_old_seg_node_pt = first_old_seg_ele_pt->node_pt(nnod-1);
4773  }
4774 
4775  // Get access to the last element on the segment
4776  FiniteElement* last_old_seg_ele_pt =
4777  old_segment_sorted_ele_pt[old_is].back();
4778 
4779  // Get the last node of the current segment
4780  Node *last_old_seg_node_pt = last_old_seg_ele_pt->node_pt(nnod-1);
4781  if (old_is_inverted[last_old_seg_ele_pt])
4782  {
4783  last_old_seg_node_pt = last_old_seg_ele_pt->node_pt(0);
4784  }
4785  // Check if the segment is inverted, if that is the case then
4786  // also invert the nodes
4787  if (old_inverted_segment)
4788  {
4789  Node* temp_node_pt = first_old_seg_node_pt;
4790  first_old_seg_node_pt = last_old_seg_node_pt;
4791  last_old_seg_node_pt = temp_node_pt;
4792  }
4793 
4794  // We have the first and last node of the old segment (input
4795  // segment), now identify in which segment, of those with only
4796  // nonhalo face elements, they are
4797  for (unsigned is = 0; is < nsegments; is++)
4798  {
4799  if (!done_segment[is])
4800  {
4801  // Go through the nodes of the current segment and try to find
4802  // the old nodes
4803  bool found_first_old_seg_node = false;
4804  bool found_last_old_seg_node = false;
4805  bool same_order = false;
4806 
4807  // Get the first node of the current segment
4808  FiniteElement* first_seg_ele_pt = segment_sorted_ele_pt[is].front();
4809  Node* first_seg_node_pt = first_seg_ele_pt->node_pt(0);
4810  if (is_inverted[first_seg_ele_pt])
4811  {first_seg_node_pt = first_seg_ele_pt->node_pt(nnod-1);}
4812 
4813  // Get the arclength for the first node
4814  const double segment_first_node_zeta =
4815  sorted_segment_node_arclength[is][0];
4816 
4817  // Get the node coordinates for the first node
4818  Vector<double> first_node_coord(2);
4819  for (unsigned i = 0; i < 2; i++)
4820  {first_node_coord[i] = first_seg_node_pt->x(i);}
4821 
4822  // Get the last node of the current segment
4823  FiniteElement* last_seg_ele_pt = segment_sorted_ele_pt[is].back();
4824  Node* last_seg_node_pt = last_seg_ele_pt->node_pt(nnod-1);
4825  if (is_inverted[last_seg_ele_pt])
4826  {last_seg_node_pt = last_seg_ele_pt->node_pt(0);}
4827 
4828  // Get the arclength for the last node
4829  const double segment_final_node_zeta = segment_arclength[is];
4830 
4831  // Get the node coordinates for the last node
4832  Vector<double> last_node_coord(2);
4833  for (unsigned i = 0; i < 2; i++)
4834  {last_node_coord[i] = last_seg_node_pt->x(i);}
4835 
4836  // Temporary storage for the nodes of the current segment
4837  Vector<Node*> segment_node_pt = sorted_segment_all_nodes_pt[is];
4838  // Get the number of nodes in the segment
4839  const unsigned nsegment_node = segment_node_pt.size();
4840  for (unsigned in = 0; in < nsegment_node; in++)
4841  {
4842  Node* current_node_pt = segment_node_pt[in];
4843  if (!found_first_old_seg_node &&
4844  first_old_seg_node_pt == current_node_pt)
4845  {
4846  // Get the arclength assigned to the node on the old
4847  // segment
4848  const double current_node_zeta =
4849  sorted_segment_node_arclength[is][in];
4850 
4851  // Now check if the new segment has the same orientation
4852  // as the old one
4853  if (!found_last_old_seg_node) // has the same orientation
4854  {
4855  // Re-assign the first node coordinates
4856  Boundary_segment_initial_coordinate[b][is] = first_node_coord;
4857 
4858  // Check if the boundary has an associated GeomObject
4859  if (this->boundary_geom_object_pt(b)!=0)
4860  {
4861  // Assign the zeta values if the current segment has the
4862  // nodes of the old one
4863 
4864  // If we are in the same order then pass the values as
4865  // they are
4866  Boundary_segment_initial_zeta[b][is] =
4867  initial_zeta_segment[is];
4868 
4869  } // if (this->boundary_geom_object_pt(b)!=0)
4870  else
4871  {
4872  // Get the distance to the first node
4873  const double distance =
4874  std::fabs(current_node_zeta - segment_first_node_zeta);
4875 
4876  double new_initial_arclength = old_initial_arclength;
4877 
4878  // Now check if the zeta values are in increasing order
4879  if (old_increasing_order)
4880  {
4881  // Substract the distance
4882  new_initial_arclength-= distance;
4883  }
4884  else
4885  {
4886  // Add the distance
4887  new_initial_arclength+= distance;
4888  }
4889 
4890  // Re-assign the initial arclength for the current segment
4891  Boundary_segment_initial_arclength[b][is] =
4892  new_initial_arclength;
4893 
4894  } // else if (this->boundary_geom_object_pt(b)!=0)
4895  } // if (!found_last_old_seg_node)
4896  else // has different orientation
4897  {
4898  // Re-assign the first node coordinates
4899  Boundary_segment_initial_coordinate[b][is] = last_node_coord;
4900 
4901  // Check if the boundary has an associated GeomObject
4902  if (this->boundary_geom_object_pt(b)!=0)
4903  {
4904  // Assign the zeta values if the current segment has the
4905  // nodes of the old one
4906 
4907  // Not the same order, we need to copy the zeta values
4908  // from the other end, the inverted flag is changed at
4909  // the end. Copy the value from the final end
4910  Boundary_segment_initial_zeta[b][is] =
4911  final_zeta_segment[is];
4912 
4913  } // if (this->boundary_geom_object_pt(b)!=0)
4914  else
4915  {
4916  // Get the distance to the final node
4917  const double distance =
4918  std::fabs(current_node_zeta - segment_final_node_zeta);
4919 
4920  double new_initial_arclength = old_initial_arclength;
4921 
4922  // Now check if the zeta values are in increasing order
4923  if (old_increasing_order)
4924  {
4925  // Substract the distance
4926  new_initial_arclength-= distance;
4927  }
4928  else
4929  {
4930  // Add the distance
4931  new_initial_arclength+= distance;
4932  }
4933 
4934  // Re-assign the initial arclength for the current segment
4935  Boundary_segment_initial_arclength[b][is] =
4936  new_initial_arclength;
4937 
4938  } // else if (this->boundary_geom_object_pt(b)!=0)
4939  } // else if (!found_last_old_seg_node)
4940 
4941  // Mark as found the first node
4942  found_first_old_seg_node = true;
4943 
4944  }
4945  // if (!found_first_old_seg_node &&
4946  // first_old_seg_node_pt == current_node_pt)
4947 
4948  // If we found first the first node then the segments have
4949  // the same order
4950  if (found_first_old_seg_node && !found_last_old_seg_node)
4951  {same_order = true;}
4952 
4953  if (!found_last_old_seg_node &&
4954  last_old_seg_node_pt == current_node_pt)
4955  {
4956  // Get the boundary coordinates assigned to the node on
4957  // the old segment
4958  const double current_node_zeta =
4959  sorted_segment_node_arclength[is][in];
4960 
4961  // Now check if the new segment has the same orientation
4962  // as the old one
4963  if (found_first_old_seg_node) // has the same orientation
4964  {
4965  // Re-assign the last node coordinates
4966  Boundary_segment_final_coordinate[b][is] = last_node_coord;
4967 
4968  // Check if the boundary has an associated GeomObject
4969  if (this->boundary_geom_object_pt(b)!=0)
4970  {
4971  // Assign the zeta values if the current segment has the
4972  // nodes of the old one
4973 
4974  // If we are in the same order then pass the values as
4975  // they are
4976  Boundary_segment_final_zeta[b][is] =
4977  final_zeta_segment[is];
4978 
4979  } // if (this->boundary_geom_object_pt(b)!=0)
4980  else
4981  {
4982  // Get the distance to the last node
4983  const double distance =
4984  std::fabs(current_node_zeta - segment_final_node_zeta);
4985 
4986  double new_final_arclength = old_final_arclength;
4987 
4988  // Now check if the zeta values are in increasing order
4989  if (old_increasing_order)
4990  {
4991  // Add the distance
4992  new_final_arclength+= distance;
4993  }
4994  else
4995  {
4996  // Substract the distance
4997  new_final_arclength-= distance;
4998  }
4999 
5000  // Re-assign the final arclength for the current segment
5001  Boundary_segment_final_arclength[b][is] = new_final_arclength;
5002 
5003  } // else if (this->boundary_geom_object_pt(b)!=0)
5004  } // if (found_first_old_seg_node)
5005  else
5006  {
5007  // Re-assign the last node coordinates
5008  Boundary_segment_final_coordinate[b][is] = first_node_coord;
5009 
5010  // Check if the boundary has an associated GeomObject
5011  if (this->boundary_geom_object_pt(b)!=0)
5012  {
5013  // Assign the zeta values if the current segment has the
5014  // nodes of the old one
5015 
5016  // Not the same order, we need to copy the zeta values
5017  // from the other end, the inverted flag is changed at
5018  // the end. Copy the value from the initial end
5019  Boundary_segment_final_zeta[b][is] =
5020  initial_zeta_segment[is];
5021 
5022  } // if (this->boundary_geom_object_pt(b)!=0)
5023  else
5024  {
5025  // Get the distance to the last node
5026  const double distance =
5027  std::fabs(current_node_zeta - segment_first_node_zeta);
5028 
5029  double new_final_arclength = old_final_arclength;
5030 
5031  // Now check if the zeta values are in increasing order
5032  if (old_increasing_order)
5033  {
5034  // Add the distance
5035  new_final_arclength+= distance;
5036  }
5037  else
5038  {
5039  // Substract the distance
5040  new_final_arclength-= distance;
5041  }
5042 
5043  // Re-assign the final arclength for the current segment
5044  Boundary_segment_final_arclength[b][is] = new_final_arclength;
5045 
5046  } // else if (this->boundary_geom_object_pt(b)!=0)
5047  } // if (found_first_old_seg_node)
5048 
5049  // Mark as found the last node
5050  found_last_old_seg_node = true;
5051 
5052  } // if (!found_last_old_seg_node &&
5053  // last_old_seg_node_pt == current_node_pt)
5054 
5055  // If we found the last node first then the segments have
5056  // not the same order
5057  if (!found_first_old_seg_node && found_last_old_seg_node)
5058  {same_order = false;}
5059 
5060  if (found_first_old_seg_node && found_last_old_seg_node)
5061  {
5062  // Check if necessary to change the information that
5063  // states if a segment is inverted or not
5064  if (same_order)
5065  {Boundary_segment_inverted[b][is] = old_inverted_segment;}
5066  else
5067  {Boundary_segment_inverted[b][is] = !old_inverted_segment;}
5068 
5069  // Mark the segment as done
5070  done_segment[is] = true;
5071 
5072  // Increase the number of re-assigned segments
5073  re_assigned_segments++;
5074 
5075  // Break the for that look for the nodes in the segments
5076  break;
5077  }
5078 
5079  } // for (in < nsegment_node)
5080 
5081 #ifdef PARANOID
5082  if ((found_first_old_seg_node && !found_last_old_seg_node) ||
5083  (!found_first_old_seg_node && found_last_old_seg_node))
5084  {
5085  std::stringstream error_message;
5086  error_message
5087  << "Working with boundary ("<< b << ").\nOnly the first node or "
5088  << "the last node of the old segment (" << old_is << ") was\n"
5089  << "found. Both, first and last node should have been found in "
5090  << "the same segment!!!.\n"
5091  << "Found first seg node:" << found_first_old_seg_node << "\n"
5092  << "Found last seg node:" << found_last_old_seg_node << "\n\n";
5093  throw OomphLibError(error_message.str(),
5094  "TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary()",
5095  OOMPH_EXCEPTION_LOCATION);
5096  }
5097 #endif
5098 
5099  } // if (!done_segment[is])
5100  } // for (is < nsegments)
5101  } // for (old_is < old_nsegments)
5102 
5103  // For those segments not identified set dummy values, the boundary
5104  // coordinates should be corrected at the synchronisation stage
5105 
5106  // loop over the new segments and check if there not identified
5107  // segments
5108  for (unsigned is = 0; is < nsegments; is++)
5109  {
5110  // Was the segment identified
5111  if (!done_segment[is])
5112  {
5113  // Get the first node of the current segment
5114  FiniteElement* first_seg_ele_pt =
5115  segment_sorted_ele_pt[is].front();
5116  // Number of nodes
5117  const unsigned nnod = first_seg_ele_pt->nnode();
5118 
5119  Node* first_seg_node_pt = first_seg_ele_pt->node_pt(0);
5120  if (is_inverted[first_seg_ele_pt])
5121  {first_seg_node_pt = first_seg_ele_pt->node_pt(nnod-1);}
5122 
5123  // Get the arclength for the first node
5124  const double segment_first_node_zeta =
5125  sorted_segment_node_arclength[is][0];
5126 
5127  // Get the node coordinates for the first node
5128  Vector<double> first_node_coord(2);
5129  for (unsigned i = 0; i < 2; i++)
5130  {first_node_coord[i] = first_seg_node_pt->x(i);}
5131 
5132  // Get the last node of the current segment
5133  FiniteElement* last_seg_ele_pt =
5134  segment_sorted_ele_pt[is].back();
5135  Node* last_seg_node_pt = last_seg_ele_pt->node_pt(nnod-1);
5136  if (is_inverted[last_seg_ele_pt])
5137  {last_seg_node_pt = last_seg_ele_pt->node_pt(0);}
5138 
5139  // Get the arclength for the last node
5140  const double segment_final_node_zeta = segment_arclength[is];
5141 
5142  // Get the node coordinates for the last node
5143  Vector<double> last_node_coord(2);
5144  for (unsigned i = 0; i < 2; i++)
5145  {last_node_coord[i] = last_seg_node_pt->x(i);}
5146 
5147  // Re-assign the initial node coordinates
5148  Boundary_segment_initial_coordinate[b][is] = first_node_coord;
5149 
5150  // Check if the boundary has an associated GeomObject
5151  if (this->boundary_geom_object_pt(b)!=0)
5152  {
5153  // Assign the zeta values if the current segment has the
5154  // nodes of the old one
5155 
5156  // If we are in the same order then pass the values as
5157  // they are
5158  Boundary_segment_initial_zeta[b][is] =
5159  initial_zeta_segment[is];
5160 
5161  } // if (this->boundary_geom_object_pt(b)!=0)
5162  else
5163  {
5164  // Re-assign the initial arclength for the current segment
5165  Boundary_segment_initial_arclength[b][is] =
5166  segment_first_node_zeta;
5167 
5168  } // else if (this->boundary_geom_object_pt(b)!=0)
5169 
5170  // Re-assign the initial node coordinates
5171  Boundary_segment_final_coordinate[b][is] = last_node_coord;
5172 
5173  // Check if the boundary has an associated GeomObject
5174  if (this->boundary_geom_object_pt(b)!=0)
5175  {
5176  // Assign the zeta values if the current segment has the
5177  // nodes of the old one
5178 
5179  // If we are in the same order then pass the values as
5180  // they are
5181  Boundary_segment_final_zeta[b][is] =
5182  final_zeta_segment[is];
5183 
5184  } // if (this->boundary_geom_object_pt(b)!=0)
5185  else
5186  {
5187  // Re-assign the final arclength for the current segment
5188  Boundary_segment_final_arclength[b][is] =
5189  segment_final_node_zeta;
5190 
5191  } // else if (this->boundary_geom_object_pt(b)!=0)
5192 
5193  Boundary_segment_inverted[b][is] = 0;
5194 
5195  // Mark the segment as done
5196  done_segment[is] = true;
5197 
5198  // Increase the number of re-assigned segments
5199  re_assigned_segments++;
5200 
5201  } // if (!done_segment[is])
5202 
5203  } // for (is < nsegments)
5204 
5205 #ifdef PARANOID
5206  // Compare the number of new segments identified with the old segments
5207  if (re_assigned_segments != nsegments)
5208  {
5209  std::stringstream error_message;
5210  error_message
5211  << "Working with boundary ("<< b << ").\nThe number of re-assigned "
5212  << "segments (" << re_assigned_segments
5213  << ") is different from the number\nof segments ("<< nsegments
5214  << ")\n\n";
5215  throw OomphLibError(error_message.str(),
5216  "TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary()",
5217  OOMPH_EXCEPTION_LOCATION);
5218  } // if (re_assigned_segments != nsegments)
5219 #endif
5220 
5221  // Clean all the created face elements
5222  for (unsigned i = 0; i < nele; i++)
5223  {
5224  delete face_el_pt[i];
5225  face_el_pt[i] = 0;
5226  }
5227 
5228  }
5229 
5230  ///=====================================================================
5231  /// Select face elements from a given boundary. In case the we are
5232  /// dealing with an internal boundary we use a set of criterias to
5233  /// decide which of the two face elements should be used on represent
5234  /// the internal boundary. We return the face elements, halo or
5235  /// haloed on this processor that form the boundary. The caller method
5236  /// should be in charge of selecting nonhalo elements and deleting the face
5237  /// elements created by this method
5238  /// =====================================================================
5239  template <class ELEMENT>
5241  select_boundary_face_elements(Vector<FiniteElement*> &face_ele_pt,
5242  const unsigned &b,
5243  bool &is_internal_boundary,
5244  std::map<FiniteElement*,FiniteElement*>
5245  &face_to_bulk_element_pt)
5246  {
5247  // Get the communicator of the mesh
5248  OomphCommunicator* comm_pt = this->communicator_pt();
5249 
5250  const unsigned my_rank = comm_pt->my_rank();
5251 
5252  // ------------------------------------------------------------------
5253  // 1) Get the face elements associated with the current boundary
5254  // ------------------------------------------------------------------
5255 
5256  // Temporary storage for face elements (do not take care of
5257  // repeated face elements)
5258  Vector<FiniteElement*> tmp_face_ele_pt;
5259 
5260  const unsigned nregions = this->nregion();
5261 
5262  // If there is more than one region then only use boundary
5263  // coordinates from the bulk side (region 0)
5264  if (nregions > 1)
5265  {
5266  for (unsigned ir = 0 ; ir < nregions; ir++)
5267  {
5268  const unsigned region_id =
5269  static_cast<unsigned>(this->Region_attribute[ir]);
5270 
5271  // Loop over all elements on boundaries in region -ir-
5272  const unsigned nele_in_region =
5273  this->nboundary_element_in_region(b, region_id);
5274 
5275  // Only bother to do anything else, if there are elements
5276  // associated with the boundary and the current region
5277  if (nele_in_region > 0)
5278  {
5279  // Loop over the bulk elements adjacent to boundary b
5280  for (unsigned e = 0; e < nele_in_region; e++)
5281  {
5282  // Get pointer to the bulk element that is adjacent
5283  // to boundary b
5284  FiniteElement* bulk_ele_pt =
5285  this->boundary_element_in_region_pt(b, region_id, e);
5286 
5287  // Get the index of the face of element e along
5288  // boundary b
5289  int face_index =
5290  this->face_index_at_boundary_in_region(b,region_id,e);
5291 
5292  // Create the face element
5293  FiniteElement* tmp_face_el_pt =
5294  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
5295 
5296  // Associated the face element with the bulk
5297  face_to_bulk_element_pt[tmp_face_el_pt] = bulk_ele_pt;
5298 
5299  // ... and add it to the tmp storage for all the
5300  // face elements, do not take care for repeated
5301  // ones (at the moment)
5302  tmp_face_ele_pt.push_back(tmp_face_el_pt);
5303 
5304  } // for (e < nele_in_region)
5305 
5306  } // if (nele_in_region > 0)
5307 
5308  } // for (ir < n_regions)
5309 
5310  } // if (n_regions > 1)
5311 
5312  //Otherwise it's just the normal boundary functions
5313  else
5314  {
5315  // Loop over all elements on boundaries
5316  const unsigned nbound_ele = this->nboundary_element(b);
5317 
5318  //Only bother to do anything else, if there are elements
5319  if (nbound_ele > 0)
5320  {
5321  // Loop over the bulk elements adjacent to boundary b
5322  for (unsigned e = 0; e < nbound_ele; e++)
5323  {
5324  // Get pointer to the bulk element that is adjacent to
5325  // boundary b
5326  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
5327 
5328  // Get the index of the face of element e along
5329  // boundary b
5330  int face_index = this->face_index_at_boundary(b, e);
5331 
5332  // Create the face element
5333  FiniteElement* tmp_face_el_pt =
5334  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
5335 
5336  // Associated the face element with the bulk
5337  face_to_bulk_element_pt[tmp_face_el_pt] = bulk_ele_pt;
5338 
5339  // ... and add it to the tmp storage for all the face
5340  // elements, do not care for repeated ones (at the
5341  // moment)
5342  tmp_face_ele_pt.push_back(tmp_face_el_pt);
5343 
5344  } // (e < nbound_ele)
5345 
5346  } // (nbound_ele > 0)
5347 
5348  } // else (n_regions > 1)
5349 
5350  // map to know which face element has been already done
5351  std::map<FiniteElement*,bool> done_face;
5352 
5353  // Set the flag to indicate if we are working with an internal
5354  // boundary
5355  is_internal_boundary = false;
5356 
5357  // Free the memory of the elements in this container (only used
5358  // when working with internal boundaries)
5359  Vector<FiniteElement*> free_memory_face_ele_pt;
5360 
5361  // Get the number of face elements in the boundary (including
5362  // repeated)
5363  const unsigned n_tmp_face_ele = tmp_face_ele_pt.size();
5364  for (unsigned ie = 0; ie < n_tmp_face_ele; ie++)
5365  {
5366  // Get the possible main element
5367  FiniteElement* main_face_ele_pt = tmp_face_ele_pt[ie];
5368  if (!done_face[main_face_ele_pt])
5369  {
5370  // Mark the face element as done
5371  done_face[main_face_ele_pt] = true;
5372  // Get the number of nodes for the face element
5373  const unsigned nnodes = main_face_ele_pt->nnode();
5374  // Get the first and last node of the main face element
5375  Node* main_first_node_pt = main_face_ele_pt->node_pt(0);
5376  Node* main_last_node_pt = main_face_ele_pt->node_pt(nnodes-1);
5377  // Look for the other side face element (we can start from
5378  // the next one, all previous face elements have been
5379  // already identified with its other side face)
5380  for (unsigned iie = ie + 1; iie < n_tmp_face_ele; iie++)
5381  {
5382  // Get the possible dependant element
5383  FiniteElement* dependant_face_ele_pt = tmp_face_ele_pt[iie];
5384  if (!done_face[dependant_face_ele_pt])
5385  {
5386  // Get the first and last node of the dependant
5387  // face element
5388  Node* dependant_first_node_pt =
5389  dependant_face_ele_pt->node_pt(0);
5390  Node* dependant_last_node_pt =
5391  dependant_face_ele_pt->node_pt(nnodes-1);
5392  // Check if the nodes at the ends of both face
5393  // elements match (also check the reversed case)
5394  if (((dependant_first_node_pt == main_first_node_pt) &&
5395  (dependant_last_node_pt == main_last_node_pt)) ||
5396  ((dependant_first_node_pt == main_last_node_pt) &&
5397  (dependant_last_node_pt == main_first_node_pt)))
5398  {
5399  // Set the flag to indicate we are working with an
5400  // internal boundary
5401  is_internal_boundary = true;
5402  // Mark the face element as done
5403  done_face[dependant_face_ele_pt] = true;
5404 
5405  // Now choose which face element will be used
5406  // as the main element. We get the processor in
5407  // charge of the element and choose the one
5408  // with the highest processor in charge or the
5409  // bottom-left bulk element in case the both
5410  // faces are on the same processor
5411 
5412  // Get the bulk element for each face element
5413  // (the main and the dependant face element)
5414  FiniteElement *main_bulk_ele_pt =
5415  face_to_bulk_element_pt[main_face_ele_pt];
5416  FiniteElement *dependant_bulk_ele_pt =
5417  face_to_bulk_element_pt[dependant_face_ele_pt];
5418 
5419  // Get the processor in charge for each bulk
5420  // element
5421  int processor_in_charge_main_bulk_ele =
5422  main_bulk_ele_pt->non_halo_proc_ID();
5423  int processor_in_charge_dependant_bulk_ele =
5424  dependant_bulk_ele_pt->non_halo_proc_ID();
5425 
5426  // If the processor in charge is negative the
5427  // element is not halo, therefore the processor
5428  // in charge is the current one
5429  if (processor_in_charge_main_bulk_ele < 0)
5430  {
5431  processor_in_charge_main_bulk_ele=
5432  static_cast<int>(my_rank);
5433  }
5434  if (processor_in_charge_dependant_bulk_ele < 0)
5435  {
5436  processor_in_charge_dependant_bulk_ele=
5437  static_cast<int>(my_rank);
5438  }
5439 
5440  // Flag to know if add the main or dependant
5441  // face element
5442  bool add_main_face_element = true;
5443  if (processor_in_charge_dependant_bulk_ele >
5444  processor_in_charge_main_bulk_ele)
5445  {
5446  // Include the dependant element
5447  add_main_face_element = false;
5448  }
5449  else if (processor_in_charge_main_bulk_ele ==
5450  processor_in_charge_dependant_bulk_ele)
5451  {
5452  // When the processor in charge for both
5453  // elements is the same then use the
5454  // bottom-left criteria on the bulk
5455  // elements to choose the main face element
5456  Vector<double> main_ele_coordinates(2);
5457  Vector<double> dependant_ele_coordinates(2);
5458  // Get the number of nodes on the bulk
5459  // elements
5460  const unsigned n_bulk_nodes =
5461  main_bulk_ele_pt->nnode();
5462  for (unsigned inode = 0; inode < n_bulk_nodes;
5463  inode++)
5464  {
5465  for (unsigned idim = 0; idim < 2; idim++)
5466  {
5467  main_ele_coordinates[idim]+=
5468  main_bulk_ele_pt->node_pt(inode)->
5469  x(idim);
5470  dependant_ele_coordinates[idim]+=
5471  dependant_bulk_ele_pt->node_pt(inode)->
5472  x(idim);
5473  } // (idim < 2)
5474 
5475  } // (inode < n_bulk_nodes)
5476 
5477  // Get the average of the nodes coordinates
5478  for (unsigned idim = 0; idim < 2; idim++)
5479  {
5480  main_ele_coordinates[idim]/=
5481  (double)n_bulk_nodes;
5482  dependant_ele_coordinates[idim]/=
5483  (double)n_bulk_nodes;
5484  }
5485 
5486  // Once we know the average coordinates for
5487  // each element then we choose the one with
5488  // the bottom-left averaged coordinates
5489  if (dependant_ele_coordinates[1] <
5490  main_ele_coordinates[1])
5491  {add_main_face_element = false;}
5492  else if(dependant_ele_coordinates[1]==
5493  main_ele_coordinates[1])
5494  {
5495  // The left-most element
5496  if(dependant_ele_coordinates[0] <
5497  main_ele_coordinates[0])
5498  {add_main_face_element = false;}
5499  }
5500  } // else -- The processor in charge is the
5501  // same for both elements
5502 
5503  if (add_main_face_element)
5504  {
5505  // Add the main face element to the storage
5506  // so we get the halo and haloed nodes from
5507  // it
5508  face_ele_pt.push_back(main_face_ele_pt);
5509  // Mark the dependat face element to free
5510  // its memory
5511  free_memory_face_ele_pt.
5512  push_back(dependant_face_ele_pt);
5513  }
5514  else
5515  {
5516  // Add the dependant face element to the
5517  // storage so we get the halo and haloed
5518  // nodes from it
5519  face_ele_pt.push_back(dependant_face_ele_pt);
5520  // Mark the main face element to free its
5521  // memory
5522  free_memory_face_ele_pt.
5523  push_back(main_face_ele_pt);
5524  }
5525 
5526  // Break the for to look for the next face
5527  // element
5528  break;
5529 
5530  } // if -- matching of nodes from main ele and
5531  // dependant ele
5532 
5533  } // if (!done_face[dependant_face_ele_pt])
5534 
5535  } // for (iie < n_tmp_face_ele)
5536 
5537  } // if (!done_face[main_face_ele_pt])
5538 
5539  } // for (ie < n_tmp_face_ele)
5540 
5541  // Are there any face element to free its memory
5542  const unsigned n_free_face_ele = free_memory_face_ele_pt.size();
5543  if (n_free_face_ele == 0)
5544  {
5545  // If there is not face elements to free memory that means that
5546  // we are not working with an internal boundary, therefore copy
5547  // all the element from the tmp face elements into the face
5548  // elements container
5549 
5550  // Resize the container
5551  face_ele_pt.resize(n_tmp_face_ele);
5552  // loop over the elements and copy them
5553  for (unsigned i = 0; i < n_tmp_face_ele; i++)
5554  {
5555  face_ele_pt[i] = tmp_face_ele_pt[i];
5556  } // for (i < n_tmp_face_ele)
5557 
5558  } // if (n_free_face_ele == 0)
5559  else
5560  {
5561  // ... otherwise free the memory of the indicated elements
5562  // loop over the elements to free its memory
5563  for (unsigned i = 0; i < n_free_face_ele; i++)
5564  {
5565  delete free_memory_face_ele_pt[i];
5566  free_memory_face_ele_pt[i] = 0;
5567  } // for (i < n_free_face_ele)
5568  }
5569 
5570  }
5571 
5572  ///========================================================================
5573  /// In charge of sinchronize the boundary coordinates for internal
5574  /// boundaries that were split as part of the distribution
5575  /// process. Called after setup_boundary_coordinates() for the
5576  /// original mesh only
5577  ///========================================================================
5578  template <class ELEMENT>
5581  {
5582  // ------------------------------------------------------------------
5583  // First: Get the face elements associated with the current boundary
5584  // ------------------------------------------------------------------
5585 
5586  // Get the communicator of the mesh
5587  OomphCommunicator* comm_pt = this->communicator_pt();
5588 
5589  const unsigned nproc = comm_pt->nproc();
5590  const unsigned my_rank = comm_pt->my_rank();
5591 
5592  // Temporary storage for face elements (do not take care of repeated
5593  // face elements)
5594  Vector<FiniteElement*> tmp_face_ele_pt;
5595 
5596  const unsigned nregions = this->nregion();
5597 
5598  // map to associate the face element to the bulk element, necessary
5599  // to get the processor in charge for the halo elements
5600  std::map<FiniteElement*,FiniteElement*> face_to_bulk_element_pt;
5601 
5602  // If there is more than one region then only use boundary
5603  // coordinates from the bulk side (region 0)
5604  if (nregions > 1)
5605  {
5606  for (unsigned ir = 0 ; ir < nregions; ir++)
5607  {
5608  const unsigned region_id =
5609  static_cast<unsigned>(this->Region_attribute[ir]);
5610 
5611  // Loop over all elements on boundaries in region -ir-
5612  const unsigned nele_in_region =
5613  this->nboundary_element_in_region(b, region_id);
5614 
5615  // Only bother to do anything else, if there are elements
5616  // associated with the boundary and the current region
5617  if (nele_in_region > 0)
5618  {
5619  // Loop over the bulk elements adjacent to boundary b
5620  for (unsigned e = 0; e < nele_in_region; e++)
5621  {
5622  // Get pointer to the bulk element that is adjacent to boundary b
5623  FiniteElement* bulk_ele_pt =
5624  this->boundary_element_in_region_pt(b, region_id, e);
5625 
5626  // Get the index of the face of element e along boundary b
5627  int face_index=this->face_index_at_boundary_in_region(b,region_id,e);
5628 
5629  // Create the face element
5630  FiniteElement* tmp_face_el_pt =
5631  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
5632 
5633  // ... and add it to the tmp storage for all the face
5634  // elements, do not take care for repeated ones (at the
5635  // moment)
5636  tmp_face_ele_pt.push_back(tmp_face_el_pt);
5637  // Create the map to know if the element is halo
5638  face_to_bulk_element_pt[tmp_face_el_pt] = bulk_ele_pt;
5639 
5640  } // for (e < nele_in_region)
5641 
5642  } // if (nele_in_region > 0)
5643 
5644  } // for (ir < n_regions)
5645 
5646  } // if (n_regions > 1)
5647 
5648  //Otherwise it's just the normal boundary functions
5649  else
5650  {
5651  // Loop over all elements on boundaries
5652  const unsigned nbound_ele = this->nboundary_element(b);
5653 
5654  //Only bother to do anything else, if there are elements
5655  if (nbound_ele > 0)
5656  {
5657  // Loop over the bulk elements adjacent to boundary b
5658  for (unsigned e = 0; e < nbound_ele; e++)
5659  {
5660  // Get pointer to the bulk element that is adjacent to boundary b
5661  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
5662 
5663  // Get the index of the face of element e along boundary b
5664  int face_index = this->face_index_at_boundary(b, e);
5665 
5666  // Create the face element
5667  FiniteElement* tmp_face_el_pt =
5668  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
5669 
5670  // ... and add it to the tmp storage for all the face
5671  // elements, do not care for repeated ones (at the moment)
5672  tmp_face_ele_pt.push_back(tmp_face_el_pt);
5673  // Create the map to know if the element is halo
5674  face_to_bulk_element_pt[tmp_face_el_pt] = bulk_ele_pt;
5675 
5676  } // (e < nbound_ele)
5677 
5678  } // (nbound_ele > 0)
5679 
5680  } // else (n_regions > 1)
5681 
5682  // Temporary storage for one side face elements. In case we are
5683  // working with an internal boundary here we store only one of the
5684  // face elements that are at each side of the boundary
5685  Vector<FiniteElement*> face_ele_pt;
5686 
5687  // map to know which face element has been already done
5688  std::map<FiniteElement*,bool> done_face;
5689 
5690  // Flag to indicate if we are working with an internal boundary
5691  bool is_internal_boundary = false;
5692 
5693 #ifdef PARANOID
5694  // Flag to indicate if we are working with an internal boundary (paranoid)
5695  bool is_internal_boundary_paranoid = false;
5696 
5697  // Count the number of other side face elements found in case we are
5698  // working with an internal boundary
5699  unsigned nfound_face_elements = 0;
5700 #endif
5701 
5702  // Get the number of face elements in the boundary
5703  const unsigned nbound_ele = tmp_face_ele_pt.size();
5704  for (unsigned ie = 0; ie < nbound_ele; ie++)
5705  {
5706  // Get the possible main element
5707  FiniteElement* main_face_ele_pt = tmp_face_ele_pt[ie];
5708  if (!done_face[main_face_ele_pt])
5709  {
5710  // Mark the face element as done
5711  done_face[main_face_ele_pt] = true;
5712  // Get the number of nodes for the face element
5713  const unsigned nnodes = main_face_ele_pt->nnode();
5714  // Get the first and last node of the main face element
5715  Node* main_first_node_pt = main_face_ele_pt->node_pt(0);
5716  Node* main_last_node_pt = main_face_ele_pt->node_pt(nnodes-1);
5717  // Look for the other side face element
5718  for (unsigned iie = ie + 1; iie < nbound_ele; iie++)
5719  {
5720  // Get the possible dependant element
5721  FiniteElement* dependant_face_ele_pt = tmp_face_ele_pt[iie];
5722  if (!done_face[dependant_face_ele_pt])
5723  {
5724  // Get the first and last node of the dependant face element
5725  Node* dependant_first_node_pt =
5726  dependant_face_ele_pt->node_pt(0);
5727  Node* dependant_last_node_pt =
5728  dependant_face_ele_pt->node_pt(nnodes-1);
5729  // Check if the nodes at the ends of both face elements
5730  // match (also check the reversed case)
5731  if (((dependant_first_node_pt == main_first_node_pt) &&
5732  (dependant_last_node_pt == main_last_node_pt)) ||
5733  ((dependant_first_node_pt == main_last_node_pt) &&
5734  (dependant_last_node_pt == main_first_node_pt)))
5735  {
5736 #ifdef PARANOID
5737  // Increase the number of found face elements
5738  nfound_face_elements+=2;
5739 #endif
5740  // Set the flag to indicate we are working with an
5741  // internal boundary
5742  is_internal_boundary = true;
5743  // Mark the face element as done
5744  done_face[dependant_face_ele_pt] = true;
5745 
5746  // Now choose which face element will be used as the main
5747  // element. Use the same criteria as the compute segments
5748  // connectivity method (highest processor in charge or
5749  // bottom-left bulk element)
5750 
5751  // Get the bulk element for each face element (the main
5752  // and the dependant face element)
5753  FiniteElement *main_bulk_ele_pt =
5754  face_to_bulk_element_pt[main_face_ele_pt];
5755  FiniteElement *dependant_bulk_ele_pt =
5756  face_to_bulk_element_pt[dependant_face_ele_pt];
5757 
5758  // Get the processor in charge for each bulk element
5759  int processor_in_charge_main_bulk_ele =
5760  main_bulk_ele_pt->non_halo_proc_ID();
5761  int processor_in_charge_dependant_bulk_ele =
5762  dependant_bulk_ele_pt->non_halo_proc_ID();
5763 
5764  // If the processor in charge is negative the element is
5765  // not halo, therefore the processor in charge is the
5766  // current one
5767  if (processor_in_charge_main_bulk_ele < 0)
5768  {
5769  processor_in_charge_main_bulk_ele=static_cast<int>(my_rank);
5770  }
5771  if (processor_in_charge_dependant_bulk_ele < 0)
5772  {
5773  processor_in_charge_dependant_bulk_ele=static_cast<int>(my_rank);
5774  }
5775 
5776  // Flag to know if add the main or dependant face element
5777  bool add_main_face_element = true;
5778  if (processor_in_charge_dependant_bulk_ele >
5779  processor_in_charge_main_bulk_ele)
5780  {
5781  // Include the dependant element
5782  add_main_face_element = false;
5783  }
5784  else if (processor_in_charge_main_bulk_ele ==
5785  processor_in_charge_dependant_bulk_ele)
5786  {
5787  // When the processor in charge for both elements is the same
5788  // then use the bottom-left criteria on the bulk elements to
5789  // choose the main face element
5790  Vector<double> main_ele_coordinates(2);
5791  Vector<double> dependant_ele_coordinates(2);
5792  // Get the number of nodes on the bulk elements
5793  const unsigned n_bulk_nodes = main_bulk_ele_pt->nnode();
5794  for (unsigned inode = 0; inode < n_bulk_nodes; inode++)
5795  {
5796  for (unsigned idim = 0; idim < 2; idim++)
5797  {
5798  main_ele_coordinates[idim]+=
5799  main_bulk_ele_pt->node_pt(inode)->x(idim);
5800  dependant_ele_coordinates[idim]+=
5801  dependant_bulk_ele_pt->node_pt(inode)->x(idim);
5802  } // (idim < 2)
5803  } // (inode < n_bulk_nodes)
5804 
5805  // Get the average of the nodes coordinates
5806  for (unsigned idim = 0; idim < 2; idim++)
5807  {
5808  main_ele_coordinates[idim]/=(double)n_bulk_nodes;
5809  dependant_ele_coordinates[idim]/=(double)n_bulk_nodes;
5810  }
5811 
5812  // Once we know the average coordinates for each element
5813  // then we choose the one with the bottom-left averaged
5814  // coordinates
5815  if (dependant_ele_coordinates[1] < main_ele_coordinates[1])
5816  {add_main_face_element = false;}
5817  else if(dependant_ele_coordinates[1]==main_ele_coordinates[1])
5818  {
5819  // The left-most element
5820  if(dependant_ele_coordinates[0] < main_ele_coordinates[0])
5821  {add_main_face_element = false;}
5822  }
5823  } // else -- The processor in charge is the same for both
5824  // elements
5825 
5826  if (add_main_face_element)
5827  {
5828  // Add the main face element to the storage so we get
5829  // the halo and haloed nodes from these face element
5830  face_ele_pt.push_back(main_face_ele_pt);
5831  }
5832  else
5833  {
5834  // Add the main face element to the storage so we get
5835  // the halo and haloed nodes from these face element
5836  face_ele_pt.push_back(dependant_face_ele_pt);
5837  }
5838 
5839  // Break the for to look for the next face element
5840  break;
5841 
5842  } // if -- matching of nodes from main ele and dependant ele
5843  } // if (!done_face[dependant_face_ele_pt])
5844  } // for (iie < nbound_ele)
5845  } // if (!done_face[main_face_ele_pt])
5846  } // for (ie < nbound_ele)
5847 
5848  // Get the number of face elements
5849  const unsigned nface_ele = face_ele_pt.size();
5850 
5851 #ifdef PARANOID
5852  // Check if we are working with an internal open curve. First check
5853  // if there are elements, in a distributed approach they may be no
5854  // elements associated to the boundary
5855  if (nbound_ele > 0 && nfound_face_elements == nbound_ele)
5856  {is_internal_boundary_paranoid = true;}
5857 
5858  if (nbound_ele > 0 && is_internal_boundary_paranoid &&
5859  nbound_ele!=nface_ele*2)
5860  {
5861  std::ostringstream error_message;
5862  error_message
5863  << "The info. to perform the synchronisation of the boundary "
5864  << "coordinates was not completely established\n"
5865  << "In this case it was the number of non repeated boundary elements\n"
5866  << "Number of boundary elements: (" << nbound_ele << ")\n"
5867  << "Number of nonrepeated boundary elements: (" << nface_ele << ")\n";
5868  throw OomphLibError(error_message.str(),
5869  "TriangleMesh::synchronize_boundary_coordinates()",
5870  OOMPH_EXCEPTION_LOCATION);
5871  }
5872 #endif
5873 
5874  // ----------------------------------------------------------------
5875  // Second: Identify the halo face elements
5876  // ----------------------------------------------------------------
5877 
5878  // A flag vector to mark those face elements that are considered as
5879  // halo in the current processor
5880  std::vector<bool> is_halo_face_element(nface_ele, false);
5881 
5882  // Count the total number of non halo face elements
5883  unsigned nnon_halo_face_elements = 0;
5884 
5885  for (unsigned ie = 0; ie < nface_ele; ie++)
5886  {
5887  FiniteElement* face_el_pt = face_ele_pt[ie];
5888  // Get the bulk element
5889  FiniteElement* tmp_bulk_ele_pt = face_to_bulk_element_pt[face_el_pt];
5890  // Check if the bulk element is halo
5891  if (!tmp_bulk_ele_pt->is_halo())
5892  {
5893  is_halo_face_element[ie] = false;
5894  nnon_halo_face_elements++;
5895  }
5896  else
5897  {
5898  // Mark the face element as halo
5899  is_halo_face_element[ie] = true;
5900  }
5901  } // for (ie < nface_ele)
5902 
5903  // -----------------------------------------------------------------
5904  // Third: Go through the face elements and get the nodes from the
5905  // elements. The boundary coordinate from each node is sent to its
5906  // processor in charge, then that processor will be responsible to
5907  // send the bound coordinate to all the processors that have a halo
5908  // representation of the node
5909  // -----------------------------------------------------------------
5910 
5911  // A map to know which nodes are already done
5912  std::map<Node*,bool> done_node;
5913 
5914  // The storage for the halo nodes on face elements in this processor
5915  // with other processors
5916  Vector<Vector<Node*> > face_halo_node_pt(nproc);
5917 
5918  // The storage for the ids of the halo nodes on face elements in
5919  // this processor with other processors
5920  Vector<Vector<unsigned> > face_halo_node_id(nproc);
5921 
5922  // The storage for the haloed nodes on face elements in this
5923  // processor with other processors
5924  Vector<Vector<Node*> > face_haloed_node_pt(nproc);
5925 
5926  // The storage for the ids of the haloed nodes on face elements in
5927  // this processor with other processors
5928  Vector<Vector<unsigned> > face_haloed_node_id(nproc);
5929 
5930  // A map to know which nodes are face nodes and the processor in
5931  // charge is the current one
5932  std::map<Node*,bool> done_haloed_face_node;
5933 
5934  // Go through all the face elements
5935  for (unsigned iface = 0; iface < nface_ele; iface++)
5936  {
5937  // Only work with the non halo face elements
5938  if (!is_halo_face_element[iface])
5939  {
5940  // Get the face element
5941  FiniteElement *ele_face_pt = face_ele_pt[iface];
5942  // The number of nodes of the face elements
5943  const unsigned nnodes = ele_face_pt->nnode();
5944  // Go through all the nodes in the face element
5945  for (unsigned in = 0; in < nnodes; in++)
5946  {
5947  Node* face_node_pt = ele_face_pt->node_pt(in);
5948  // Check if node is done
5949  if (!done_node[face_node_pt])
5950  {
5951  // Mark the node as done
5952  done_node[face_node_pt] = true;
5953  // First check if the node is halo
5954  if (face_node_pt->is_halo())
5955  {
5956  // Get the processor in charge for the current node
5957  int int_nonhalo_ID = face_node_pt->non_halo_proc_ID();
5958 #ifdef PARANOID
5959  if (int_nonhalo_ID < 0)
5960  {
5961  std::ostringstream error_message;
5962  error_message
5963  << "The node was marked to be halo but the processor in "
5964  << "charge was found to be -1\n\n";
5965  throw OomphLibError(error_message.str(),
5966  "TriangleMesh::synchronize_boundary_coordinates()",
5967  OOMPH_EXCEPTION_LOCATION);
5968  }
5969 #endif
5970  const unsigned ip = static_cast<unsigned>(int_nonhalo_ID);
5971  // Add the node to the structure that holds the halo
5972  // nodes, the current processor will need to send the
5973  // info. to the processor in charge.
5974  face_halo_node_pt[ip].push_back(face_node_pt);
5975  // ... finally look for the halo id with the processor in
5976  // charge
5977 #ifdef PARANOID
5978  bool found_halo_node = false;
5979 #endif
5980  const unsigned nhalo_iproc = this->nhalo_node(ip);
5981  for (unsigned ihn = 0; ihn < nhalo_iproc; ihn++)
5982  {
5983  Node* compare_face_node_pt = this->halo_node_pt(ip, ihn);
5984  if (compare_face_node_pt == face_node_pt)
5985  {
5986  // Once found the id of the node with the processor
5987  // store the id in the proper storage
5988  face_halo_node_id[ip].push_back(ihn);
5989 #ifdef PARANOID
5990  // Set the flag to mark as found the halo node
5991  found_halo_node = true;
5992 #endif
5993  // Break the loop
5994  break;
5995  }
5996  } // for (ih < nhalo_iproc)
5997 #ifdef PARANOID
5998  if (!found_halo_node)
5999  {
6000  std::ostringstream error_message;
6001  error_message
6002  << "The halo id of the current node: ("
6003  << face_node_pt->x(0) << ", " << face_node_pt->x(1)
6004  << ") with processor (" << ip << ") was not found!!!\n\n";
6005  throw OomphLibError(error_message.str(),
6006  "TriangleMesh::synchronize_boundary_coordinates()",
6007  OOMPH_EXCEPTION_LOCATION);
6008  }
6009 #endif
6010  } // if (face_node_pt->is_halo())
6011  // If the node is not halo then it could be haloed. If that
6012  // is the case then store the processors at which the node
6013  // is haloed and its id. The info. of these nodes will be
6014  // sent to all the processors with a halo counterpart
6015  else
6016  {
6017  for (unsigned ip = 0; ip < nproc; ip++)
6018  {
6019  // Only work with processors different that the current one
6020  if (ip != my_rank)
6021  {
6022  // If the node is found to be haloed with the "ip"
6023  // processor then save the haloed id in the storage.
6024  // The current processor needs to send info. to the
6025  // other processors to establish the boundary
6026  // coordinates
6027 
6028  // Get the number of haloed nodes with processor ip
6029  const unsigned nhaloed_iproc = this->nhaloed_node(ip);
6030  for (unsigned ihdn = 0; ihdn < nhaloed_iproc; ihdn++)
6031  {
6032  Node* compare_face_node_pt=this->haloed_node_pt(ip, ihdn);
6033  if (face_node_pt == compare_face_node_pt)
6034  {
6035  // Store the node on the haloed node vector for
6036  // the corresponding processor
6037  face_haloed_node_pt[ip].push_back(face_node_pt);
6038  // Now store the halo id of the node with the
6039  // current processor
6040  face_haloed_node_id[ip].push_back(ihdn);
6041  // Mark the node as haloed with other processors,
6042  // so we know the processor in charge is the
6043  // current one "my_rank".
6044  done_haloed_face_node[face_node_pt] = true;
6045  // Break looking in the current processor, look in
6046  // the next one
6047  break;
6048  } // if (face_node_pt == compare_face_node_pt)
6049  } // for (ihdn < nhaloed_node_iproc)
6050  } // if (ip != my_rank)
6051  } // for (ip < nproc)
6052  } // else (non halo node)
6053  } // if (!done_node[node_face_pt])
6054  } // for (in < nnodes)
6055  } // if (!is_halo_face_element[iface])
6056  } // for (iface < nface_ele)
6057 
6058  // -----------------------------------------------------------------
6059  // Fourth: Go through the halo nodes, package and send the
6060  // info. necessary to identify the face nodes in the processor in
6061  // charge. Identify the haloed nodes in the processor in charge and
6062  // establish the boundary coordinates, check if those nodes are
6063  // (already) marked as faced nodes, if that is the case then do not
6064  // establish the boundary coordinates but register them to send back
6065  // the info. to all the processors that have a halo representation
6066  // of the face node
6067  // -----------------------------------------------------------------
6068 
6069  // Go through all processors
6070  for (unsigned ip = 0; ip < nproc; ip++)
6071  {
6072  // Only work with processors different than the current one
6073  if (ip != my_rank)
6074  {
6075  const unsigned nhalo_face_nodes = face_halo_node_pt[ip].size();
6076 #ifdef PARANOID
6077  if (nhalo_face_nodes!=face_halo_node_id[ip].size())
6078  {
6079  std::ostringstream error_message;
6080  error_message
6081  << "The number of found halo face nodes (" << nhalo_face_nodes
6082  << ") is different from the number of\nfound halo face ids ("
6083  << face_halo_node_id[ip].size() << ")!!!\n\n";
6084  throw OomphLibError(error_message.str(),
6085  "TriangleMesh::synchronize_boundary_coordinates()",
6086  OOMPH_EXCEPTION_LOCATION);
6087  }
6088 #endif
6089 
6090  // Container to send the info. related with the halo nodes to be
6091  // identified in the processors in charge
6092  Vector<unsigned> flat_unsigned_send_packed_data;
6093  Vector<double> flat_double_send_packed_data;
6094 
6095  // Go through the halo face nodes in the "ip" processor
6096  for (unsigned ihfn = 0; ihfn < nhalo_face_nodes; ihfn++)
6097  {
6098  // Get the "ihfn"-th face node with the "ip" processor
6099  Node *halo_face_node_pt = face_halo_node_pt[ip][ihfn];
6100  // Get the halo id with the "ip" processor
6101  const unsigned halo_id = face_halo_node_id[ip][ihfn];
6102  // Get the boundary coordinate of the node
6103  Vector<double> zeta(1);
6104  halo_face_node_pt->get_coordinates_on_boundary(b, zeta);
6105  // Store the info. in the containers
6106  flat_unsigned_send_packed_data.push_back(halo_id);
6107  flat_double_send_packed_data.push_back(zeta[0]);
6108  }
6109 
6110  // Send the info.
6111  MPI_Status status;
6112  MPI_Request request;
6113 
6114  // Processor to which send the info
6115  int send_proc = static_cast<int>(ip);
6116  // Processor from which receive the info
6117  int receive_proc = static_cast<int>(ip);
6118 
6119  // Storage to receive the info.
6120  Vector<unsigned> flat_unsigned_receive_packed_data;
6121  Vector<double> flat_double_receive_packed_data;
6122 
6123  // --------------
6124  // Unsigned data
6125  unsigned nflat_unsigned_send = flat_unsigned_send_packed_data.size();
6126  MPI_Isend(&nflat_unsigned_send,1,MPI_UNSIGNED,
6127  send_proc,1,comm_pt->mpi_comm(),&request);
6128 
6129  unsigned nflat_unsigned_receive = 0;
6130  MPI_Recv(&nflat_unsigned_receive,1,MPI_UNSIGNED,
6131  receive_proc,1,comm_pt->mpi_comm(),&status);
6132 
6133  MPI_Wait(&request,MPI_STATUS_IGNORE);
6134 
6135  if (nflat_unsigned_send!=0)
6136  {
6137  MPI_Isend(&flat_unsigned_send_packed_data[0],nflat_unsigned_send,
6138  MPI_UNSIGNED,send_proc,2,comm_pt->mpi_comm(),&request);
6139  }
6140 
6141  if (nflat_unsigned_receive!=0)
6142  {
6143  flat_unsigned_receive_packed_data.resize(nflat_unsigned_receive);
6144  MPI_Recv(&flat_unsigned_receive_packed_data[0],nflat_unsigned_receive,
6145  MPI_UNSIGNED,receive_proc,2,comm_pt->mpi_comm(),&status);
6146  }
6147 
6148  if (nflat_unsigned_send!=0)
6149  {
6150  MPI_Wait(&request,MPI_STATUS_IGNORE);
6151  }
6152 
6153  // --------------
6154  // Double data
6155  unsigned nflat_double_send = flat_double_send_packed_data.size();
6156  MPI_Isend(&nflat_double_send,1,MPI_DOUBLE,
6157  send_proc,3,comm_pt->mpi_comm(),&request);
6158 
6159  unsigned nflat_double_receive = 0;
6160  MPI_Recv(&nflat_double_receive,1,MPI_DOUBLE,
6161  receive_proc,3,comm_pt->mpi_comm(),&status);
6162 
6163  MPI_Wait(&request,MPI_STATUS_IGNORE);
6164 
6165  if (nflat_double_send!=0)
6166  {
6167  MPI_Isend(&flat_double_send_packed_data[0],nflat_double_send,
6168  MPI_DOUBLE,send_proc,4,comm_pt->mpi_comm(),&request);
6169  }
6170 
6171  if (nflat_double_receive!=0)
6172  {
6173  flat_double_receive_packed_data.resize(nflat_double_receive);
6174  MPI_Recv(&flat_double_receive_packed_data[0],nflat_double_receive,
6175  MPI_DOUBLE,receive_proc,4,comm_pt->mpi_comm(),&status);
6176  }
6177 
6178  if (nflat_double_send!=0)
6179  {
6180  MPI_Wait(&request,MPI_STATUS_IGNORE);
6181  }
6182  // --------------
6183 
6184 #ifdef PARANOID
6185  if (nflat_unsigned_receive!=nflat_double_receive)
6186  {
6187  std::ostringstream error_message;
6188  error_message
6189  << "The number of unsigned received data ("
6190  << nflat_unsigned_receive << ") is different from the "
6191  << "number\nof double received data ("
6192  << nflat_double_receive << ")!!!\n\n";
6193  throw OomphLibError(error_message.str(),
6194  "TriangleMesh::synchronize_boundary_coordinates()",
6195  OOMPH_EXCEPTION_LOCATION);
6196  }
6197 #endif
6198 
6199  // With the received info. establish the boundary coordinates
6200  // for the face nodes that this processor is in charge (haloed
6201  // nodes)
6202  for (unsigned iflat_packed = 0; iflat_packed < nflat_unsigned_receive;
6203  iflat_packed++)
6204  {
6205  // Get the haloed id for the node
6206  const unsigned haloed_id =
6207  flat_unsigned_receive_packed_data[iflat_packed];
6208  // Get the boundary coordinates
6209  Vector<double> zeta(1);
6210  zeta[0] = flat_double_receive_packed_data[iflat_packed];
6211 
6212  // Get the haloed node
6213  Node* haloed_face_node_pt = this->haloed_node_pt(ip, haloed_id);
6214 
6215  // If the node has already set the boundary coordinates then
6216  // do not establish it. This is the case for the nodes that
6217  // lie on the boundary, for those nodes not identified on the
6218  // boundary since no elements lie on the boundary but the node
6219  // is on the boundary (a corner of an element lies on the
6220  // boundary) set boundary coordinates and register them to
6221  // send their info. to the processors with a halo counterpart
6222 
6223  // If the node is not haloed face in the procesor in charge
6224  // then set the boundary coordinates and register the node to
6225  // send back the boundary coordinates to the processors with a
6226  // halo counterpart
6227  if (!done_haloed_face_node[haloed_face_node_pt])
6228  {
6229  // Establish the boundary coordinates
6230  haloed_face_node_pt->set_coordinates_on_boundary(b, zeta);
6231 
6232  // Look in all processors where the node could be halo
6233  for (unsigned iiproc = 0; iiproc < nproc; iiproc++)
6234  {
6235  // Only work with processors different than the current one
6236  if (iiproc != my_rank)
6237  {
6238  // Get the number of haloed nodes with processor iiproc
6239  const unsigned nhaloed_node_iiproc = this->nhaloed_node(iiproc);
6240  for (unsigned ihdn = 0; ihdn < nhaloed_node_iiproc; ihdn++)
6241  {
6242  Node* compare_haloed_node_pt=this->haloed_node_pt(iiproc,ihdn);
6243  if (haloed_face_node_pt == compare_haloed_node_pt)
6244  {
6245  // Store the node on the haloed node vector for the
6246  // corresponding processor
6247  face_haloed_node_pt[iiproc].push_back(haloed_face_node_pt);
6248  // Now store the halo id of the node with the current
6249  // processor
6250  face_haloed_node_id[iiproc].push_back(ihdn);
6251  // Break searching in the current processor, search in
6252  // the next one
6253  break;
6254  }// if (haloed_face_node_pt==compare_haloed_face_node_pt)
6255  } // for (ihdn < nhaloed_node_iproc)
6256  } // if (iiproc != my_rank)
6257  } // for (iiproc < nproc)
6258  } // if (!done_haloed_face_node[haloed_face_node_pt])
6259  } // for (iflat_packed < nflat_unsigned_receive)
6260  } // if (ip != my_rank)
6261  } // for (ip < nproc)
6262 
6263  // -----------------------------------------------------------------
6264  // Fifth: The boundary coordinates have been established in the
6265  // processors in charge of the nodes. Now each processor send back
6266  // the boundary coordinates to all the processors where there is a
6267  // halo representation of the node
6268  // -----------------------------------------------------------------
6269 
6270  // Go through all processors
6271  for (unsigned ip = 0; ip < nproc; ip++)
6272  {
6273  // Only work with processors different than the current one
6274  if (ip != my_rank)
6275  {
6276  // Container to send the info. of the haloed nodes to all the
6277  // processors
6278  Vector<unsigned> flat_unsigned_send_packed_data;
6279  Vector<double> flat_double_send_packed_data;
6280 
6281  // Get the total number of haloed face nodes with the "ip"
6282  // processor
6283  const unsigned nhaloed_face_nodes = face_haloed_node_pt[ip].size();
6284  // Go through the haloed face nodes in the "ip" processor
6285  for (unsigned ihdfn = 0; ihdfn < nhaloed_face_nodes; ihdfn++)
6286  {
6287  // Get the "ihdfn"-th face node with the "ip" processor
6288  Node *haloed_face_node_pt = face_haloed_node_pt[ip][ihdfn];
6289  // Get the haloed id with the "ip" processor
6290  const unsigned haloed_id = face_haloed_node_id[ip][ihdfn];
6291  // Get the boundary coordinate of the node
6292  Vector<double> zeta(1);
6293  haloed_face_node_pt->get_coordinates_on_boundary(b, zeta);
6294  // Store the info. in the containers
6295  flat_unsigned_send_packed_data.push_back(haloed_id);
6296  flat_double_send_packed_data.push_back(zeta[0]);
6297  }
6298 
6299  // Send the info.
6300  MPI_Status status;
6301  MPI_Request request;
6302 
6303  // Processor to which send the info
6304  int send_proc = static_cast<int>(ip);
6305  // Processor from which receive the info
6306  int receive_proc = static_cast<int>(ip);
6307 
6308  // Storage to receive the info.
6309  Vector<unsigned> flat_unsigned_receive_packed_data;
6310  Vector<double> flat_double_receive_packed_data;
6311 
6312  // --------------
6313  // Unsigned data
6314  unsigned nflat_unsigned_send = flat_unsigned_send_packed_data.size();
6315  MPI_Isend(&nflat_unsigned_send,1,MPI_UNSIGNED,
6316  send_proc,1,comm_pt->mpi_comm(),&request);
6317 
6318  unsigned nflat_unsigned_receive = 0;
6319  MPI_Recv(&nflat_unsigned_receive,1,MPI_UNSIGNED,
6320  receive_proc,1,comm_pt->mpi_comm(),&status);
6321 
6322  MPI_Wait(&request,MPI_STATUS_IGNORE);
6323 
6324  if (nflat_unsigned_send!=0)
6325  {
6326  MPI_Isend(&flat_unsigned_send_packed_data[0],nflat_unsigned_send,
6327  MPI_UNSIGNED,send_proc,2,comm_pt->mpi_comm(),&request);
6328  }
6329 
6330  if (nflat_unsigned_receive!=0)
6331  {
6332  flat_unsigned_receive_packed_data.resize(nflat_unsigned_receive);
6333  MPI_Recv(&flat_unsigned_receive_packed_data[0],nflat_unsigned_receive,
6334  MPI_UNSIGNED,receive_proc,2,comm_pt->mpi_comm(),&status);
6335  }
6336 
6337  if (nflat_unsigned_send!=0)
6338  {
6339  MPI_Wait(&request,MPI_STATUS_IGNORE);
6340  }
6341 
6342  // --------------
6343  // Double data
6344  unsigned nflat_double_send = flat_double_send_packed_data.size();
6345  MPI_Isend(&nflat_double_send,1,MPI_DOUBLE,
6346  send_proc,3,comm_pt->mpi_comm(),&request);
6347 
6348  unsigned nflat_double_receive = 0;
6349  MPI_Recv(&nflat_double_receive,1,MPI_DOUBLE,
6350  receive_proc,3,comm_pt->mpi_comm(),&status);
6351 
6352  MPI_Wait(&request,MPI_STATUS_IGNORE);
6353 
6354  if (nflat_double_send!=0)
6355  {
6356  MPI_Isend(&flat_double_send_packed_data[0],nflat_double_send,
6357  MPI_DOUBLE,send_proc,4,comm_pt->mpi_comm(),&request);
6358  }
6359 
6360  if (nflat_double_receive!=0)
6361  {
6362  flat_double_receive_packed_data.resize(nflat_double_receive);
6363  MPI_Recv(&flat_double_receive_packed_data[0],nflat_double_receive,
6364  MPI_DOUBLE,receive_proc,4,comm_pt->mpi_comm(),&status);
6365  }
6366 
6367  if (nflat_double_send!=0)
6368  {
6369  MPI_Wait(&request,MPI_STATUS_IGNORE);
6370  }
6371  // --------------
6372 
6373 #ifdef PARANOID
6374  if (nflat_unsigned_receive!=nflat_double_receive)
6375  {
6376  std::ostringstream error_message;
6377  error_message
6378  << "The number of unsigned received data ("
6379  << nflat_unsigned_receive << ") is different from the "
6380  << "number\nof double received data ("
6381  << nflat_double_receive << ")!!!\n\n";
6382  throw OomphLibError(error_message.str(),
6383  "TriangleMesh::synchronize_boundary_coordinates()",
6384  OOMPH_EXCEPTION_LOCATION);
6385  }
6386 #endif
6387 
6388  // With the received info. establish the boundary coordinates
6389  // received for the face nodes that this processor is not in
6390  // charge (halo nodes)
6391  for (unsigned iflat_packed = 0; iflat_packed < nflat_unsigned_receive;
6392  iflat_packed++)
6393  {
6394  // Get the halo id for the node
6395  const unsigned halo_id =
6396  flat_unsigned_receive_packed_data[iflat_packed];
6397  // Get the boundary coordinates
6398  Vector<double> zeta(1);
6399  zeta[0] = flat_double_receive_packed_data[iflat_packed];
6400 
6401  // Get the halo node
6402  Node* halo_face_node_pt = this->halo_node_pt(ip, halo_id);
6403 
6404  // It could be possible that the node has been already
6405  // established boundary coordinates since it is a halo face
6406  // node. However, for those elements not on the boundary, but
6407  // having a corner node on the boundary this procedure will
6408  // establish boundary coordinates for those nodes
6409 
6410  //this->add_boundary_node(b, halo_face_node_pt);
6411 
6412  // Establish the boundary coordinates
6413  halo_face_node_pt->set_coordinates_on_boundary(b, zeta);
6414  } // for (iflat_packed < nflat_unsigned_receive)
6415  } // if (ip != my_rank)
6416  } // for (ip < nproc)
6417 
6418  // Clean all the created face elements
6419  for (unsigned ie = 0; ie < nbound_ele; ie++)
6420  {
6421  delete tmp_face_ele_pt[ie];
6422  tmp_face_ele_pt[ie] = 0;
6423  }
6424 
6425  // Now get a new face mesh representation and fill the data for those
6426  // processors with halo segments
6427  if (is_internal_boundary)
6428  {
6429  re_scale_re_assigned_initial_zeta_values_for_internal_boundary(b);
6430  }
6431 
6432  }
6433 
6434  //======================================================================
6435  /// \short Re-assign the boundary segments initial zeta (arclength)
6436  /// for those internal boundaries that were splited during the
6437  /// distribution process (only apply for internal boundaries that
6438  /// have one face element at each side of the boundary)
6439  //======================================================================
6440  template<class ELEMENT>
6443  const unsigned& b)
6444  {
6445  // ------------------------------------------------------------------
6446  // First: Get the face elements associated with the current boundary
6447  // Only include nonhalo face elements
6448  // ------------------------------------------------------------------
6449  // Temporary storage for face elements
6450  Vector<FiniteElement*> face_el_pt;
6451 
6452  // Temporary storage for the number of elements adjacent to the
6453  // boundary
6454  unsigned nele = 0;
6455 
6456  // Temporary storage for elements adjacent to the boundary that have
6457  // a common edge (related with internal boundaries)
6458  unsigned n_repeated_ele = 0;
6459 
6460  const unsigned n_regions = this->nregion();
6461 
6462  // Temporary storage for already done nodes
6463  Vector<std::pair<Node*, Node*> > done_nodes_pt;
6464 
6465  // If there is more than one region then only use boundary
6466  // coordinates from the bulk side (region 0)
6467  if (n_regions > 1)
6468  {
6469  for (unsigned rr = 0 ; rr < n_regions; rr++)
6470  {
6471  const unsigned region_id =
6472  static_cast<unsigned>(this->Region_attribute[rr]);
6473 
6474  // Loop over all elements on boundaries in region i_r
6475  const unsigned nel_in_region =
6476  this->nboundary_element_in_region(b, region_id);
6477 
6478  unsigned nel_repetead_in_region = 0;
6479 
6480  // Only bother to do anything else, if there are elements
6481  // associated with the boundary and the current region
6482  if (nel_in_region > 0)
6483  {
6484  bool repeated = false;
6485 
6486  // Loop over the bulk elements adjacent to boundary b
6487  for (unsigned e = 0; e < nel_in_region; e++)
6488  {
6489  // Get pointer to the bulk element that is adjacent to
6490  // boundary b
6491  FiniteElement* bulk_elem_pt =
6492  this->boundary_element_in_region_pt(b, region_id, e);
6493 
6494  // Remember only to work with nonhalo elements
6495  if (bulk_elem_pt->is_halo())
6496  {
6497  n_repeated_ele++;
6498  continue;
6499  }
6500 
6501  // Find the index of the face of element e along boundary b
6502  int face_index =
6503  this->face_index_at_boundary_in_region(b,region_id,e);
6504 
6505  // Before adding the new element we need to be sure that the
6506  // edge that this element represent has not been already
6507  // added
6508  FiniteElement* tmp_ele_pt =
6509  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
6510 
6511  const unsigned n_nodes = tmp_ele_pt->nnode();
6512 
6513  std::pair<Node*, Node*> tmp_pair =
6514  std::make_pair(tmp_ele_pt->node_pt(0),
6515  tmp_ele_pt->node_pt(n_nodes - 1));
6516 
6517  std::pair<Node*, Node*> tmp_pair_inverse =
6518  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
6519  tmp_ele_pt->node_pt(0));
6520 
6521  // Search for repeated nodes
6522  const unsigned n_done_nodes = done_nodes_pt.size();
6523  for (unsigned l = 0; l < n_done_nodes; l++)
6524  {
6525  if (tmp_pair == done_nodes_pt[l] ||
6526  tmp_pair_inverse == done_nodes_pt[l])
6527  {
6528  nel_repetead_in_region++;
6529  repeated = true;
6530  break;
6531  }
6532  }
6533 
6534  // Create new face element
6535  if (!repeated)
6536  {
6537  // Add the pair of nodes (edge) to the node dones
6538  done_nodes_pt.push_back(tmp_pair);
6539  // Add the element to the face elements
6540  face_el_pt.push_back(tmp_ele_pt);
6541  }
6542  else
6543  {
6544  // Clean up
6545  delete tmp_ele_pt;
6546  tmp_ele_pt = 0;
6547  }
6548 
6549  // Re-start
6550  repeated = false;
6551 
6552  } // for nel
6553 
6554  nele += nel_in_region;
6555 
6556  n_repeated_ele += nel_repetead_in_region;
6557 
6558  } // if (nel_in_region > 0)
6559  } // for (rr < n_regions)
6560  } // if (n_regions > 1)
6561  //Otherwise it's just the normal boundary functions
6562  else
6563  {
6564  // Loop over all elements on boundaries
6565  nele = this->nboundary_element(b);
6566 
6567  //Only bother to do anything else, if there are elements
6568  if (nele > 0)
6569  {
6570  // Check for repeated ones
6571  bool repeated = false;
6572 
6573  // Loop over the bulk elements adjacent to boundary b
6574  for (unsigned e = 0; e < nele; e++)
6575  {
6576  // Get pointer to the bulk element that is adjacent to
6577  // boundary b
6578  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
6579 
6580  // Remember only to work with nonhalo elements
6581  if (bulk_elem_pt->is_halo())
6582  {
6583  n_repeated_ele++;
6584  // Skip the halo element
6585  continue;
6586  }
6587 
6588  //Find the index of the face of element e along boundary b
6589  int face_index = this->face_index_at_boundary(b, e);
6590 
6591  // Before adding the new element we need to be sure that the
6592  // edge that this element represents has not been already
6593  // added (only applies for internal boundaries)
6594  FiniteElement* tmp_ele_pt =
6595  new DummyFaceElement<ELEMENT>(bulk_elem_pt, face_index);
6596 
6597  const unsigned n_nodes = tmp_ele_pt->nnode();
6598 
6599  std::pair<Node*, Node*> tmp_pair =
6600  std::make_pair(tmp_ele_pt->node_pt(0),
6601  tmp_ele_pt->node_pt(n_nodes - 1));
6602 
6603  std::pair<Node*, Node*> tmp_pair_inverse =
6604  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
6605  tmp_ele_pt->node_pt(0));
6606 
6607  // Search for repeated nodes
6608  const unsigned n_done_nodes = done_nodes_pt.size();
6609  for (unsigned l = 0; l < n_done_nodes; l++)
6610  {
6611  if (tmp_pair == done_nodes_pt[l] ||
6612  tmp_pair_inverse == done_nodes_pt[l])
6613  {
6614  // Increase the number of repeated elements
6615  n_repeated_ele++;
6616  // Mark the element as repeated
6617  repeated = true;
6618  break;
6619  }
6620  }
6621 
6622  // Create new face element
6623  if (!repeated)
6624  {
6625  // Add the pair of nodes (edge) to the node dones
6626  done_nodes_pt.push_back(tmp_pair);
6627  // Add the element to the face elements
6628  face_el_pt.push_back(tmp_ele_pt);
6629  }
6630  else
6631  {
6632  // Free the repeated bulk element!!
6633  delete tmp_ele_pt;
6634  tmp_ele_pt = 0;
6635  }
6636 
6637  // Re-start
6638  repeated = false;
6639 
6640  } // for (e < nel)
6641  } // if (nel > 0)
6642 
6643  } // else (n_regions > 1)
6644 
6645  // Do not consider the repeated elements
6646  nele-= n_repeated_ele;
6647 
6648 #ifdef PARANOID
6649  if (nele!=face_el_pt.size())
6650  {
6651  std::ostringstream error_message;
6652  error_message
6653  << "The independet counting of face elements ("<<nele<<") for "
6654  << "boundary ("<<b<<") is different\n"
6655  << "from the real number of face elements in the container ("
6656  << face_el_pt.size() <<")\n";
6657  //<< "Possible memory leak\n"
6658  throw OomphLibError(error_message.str(),
6659  "TriangleMesh::re_scale_re_assigned_initial_zeta_values_for_internal_boundary()",
6660  OOMPH_EXCEPTION_LOCATION);
6661  }
6662 #endif
6663 
6664  // ----------------------------------------------------------------
6665  // Second: Sort the face elements (to create segments), only
6666  // consider nonhalo elements
6667  // ----------------------------------------------------------------
6668 
6669  // Get the total number of nonhalo face elements
6670  const unsigned nnon_halo_face_elements = face_el_pt.size();
6671 
6672  // The vector of list to store the "segments" that compound the
6673  // boundary (segments may appear only in a distributed mesh)
6674  Vector<std::list<FiniteElement*> > segment_sorted_ele_pt;
6675 
6676  // Number of already sorted face elements
6677  unsigned nsorted_face_elements = 0;
6678 
6679  // Keep track of who's done
6680  std::map<FiniteElement*, bool> done_el;
6681 
6682  // Keep track of which element is inverted
6683  std::map<FiniteElement*, bool> is_inverted;
6684 
6685  // Iterate until all possible segments have been created
6686  while(nsorted_face_elements < nnon_halo_face_elements)
6687  {
6688  // The ordered list of face elements (in a distributed mesh a
6689  // collection of contiguous face elements define a segment)
6690  std::list<FiniteElement*> sorted_el_pt;
6691 
6692 #ifdef PARANOID
6693  // Select an initial element for the segment
6694  bool found_initial_face_element = false;
6695 #endif
6696 
6697  FiniteElement* ele_face_pt = 0;
6698 
6699  unsigned iface = 0;
6700  for (iface = 0; iface < nele; iface++)
6701  {
6702  ele_face_pt = face_el_pt[iface];
6703  // If not done then take it as initial face element
6704  if (!done_el[ele_face_pt])
6705  {
6706 #ifdef PARANOID
6707  found_initial_face_element = true;
6708 #endif
6709  nsorted_face_elements++;
6710  iface++; // The next element number
6711  sorted_el_pt.push_back(ele_face_pt);
6712  // Mark as done
6713  done_el[ele_face_pt] = true;
6714  break;
6715  }
6716  } // for (iface < nele)
6717 
6718 #ifdef PARANOID
6719  if (!found_initial_face_element)
6720  {
6721  std::ostringstream error_message;
6722  error_message
6723  <<"Could not find an initial face element for the current segment\n";
6724  // << "----- Possible memory leak -----\n";
6725  throw OomphLibError(error_message.str(),
6726  "TriangleMesh::re_scale_re_assigned_initial_zeta_values_for_internal_boundary()",
6727  OOMPH_EXCEPTION_LOCATION);
6728  }
6729 #endif
6730 
6731  // Number of nodes
6732  const unsigned nnod = ele_face_pt->nnode();
6733 
6734  // Left and rightmost nodes (the left and right nodes of the
6735  // current face element)
6736  Node* left_node_pt = ele_face_pt->node_pt(0);
6737  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
6738 
6739  // Continue iterating if a new face element has been added to the
6740  // list
6741  bool face_element_added = false;
6742 
6743  // While a new face element has been added to the set of sorted
6744  // face elements then re-iterate
6745  do
6746  {
6747  // Start from the next face element since we have already added
6748  // the previous one as the initial face element (any previous
6749  // face element had to be added on previous iterations)
6750  for (unsigned iiface = iface; iiface < nele; iiface++)
6751  {
6752  // Re-start flag
6753  face_element_added = false;
6754 
6755  // Get the candidate element
6756  ele_face_pt = face_el_pt[iiface];
6757 
6758  // Check that the candidate element has not been done
6759  if (!(done_el[ele_face_pt]))
6760  {
6761  // Get the left and right nodes of the current element
6762  Node* local_left_node_pt = ele_face_pt->node_pt(0);
6763  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
6764 
6765  // New element fits at the left of segment and is not inverted
6766  if (left_node_pt == local_right_node_pt)
6767  {
6768  left_node_pt = local_left_node_pt;
6769  sorted_el_pt.push_front(ele_face_pt);
6770  is_inverted[ele_face_pt] = false;
6771  face_element_added = true;
6772  }
6773  // New element fits at the left of segment and is inverted
6774  else if (left_node_pt == local_left_node_pt)
6775  {
6776  left_node_pt = local_right_node_pt;
6777  sorted_el_pt.push_front(ele_face_pt);
6778  is_inverted[ele_face_pt] = true;
6779  face_element_added = true;
6780  }
6781  // New element fits on the right of segment and is not inverted
6782  else if (right_node_pt == local_left_node_pt)
6783  {
6784  right_node_pt = local_right_node_pt;
6785  sorted_el_pt.push_back(ele_face_pt);
6786  is_inverted[ele_face_pt] = false;
6787  face_element_added = true;
6788  }
6789  // New element fits on the right of segment and is inverted
6790  else if (right_node_pt == local_right_node_pt)
6791  {
6792  right_node_pt = local_left_node_pt;
6793  sorted_el_pt.push_back(ele_face_pt);
6794  is_inverted[ele_face_pt] = true;
6795  face_element_added = true;
6796  }
6797 
6798  if (face_element_added)
6799  {
6800  done_el[ele_face_pt] = true;
6801  nsorted_face_elements++;
6802  break;
6803  }
6804 
6805  } // if (!(done_el[ele_face_pt]))
6806  } // for (iiface<nnon_halo_face_element)
6807  }while(face_element_added &&
6808  (nsorted_face_elements < nnon_halo_face_elements));
6809 
6810  // Store the created segment in the vector of segments
6811  segment_sorted_ele_pt.push_back(sorted_el_pt);
6812 
6813  } // while(nsorted_face_elements < nnon_halo_face_elements);
6814 
6815  // --------------------------------------------------------------
6816  // Third: We have the face elements sorted, now assign boundary
6817  // coordinates to the nodes in the segments and compute the
6818  // arclength of the segment
6819  // --------------------------------------------------------------
6820 
6821  // Vector of sets that stores the nodes of each segment based on a
6822  // lexicographically order starting from the bottom left node of
6823  // each segment
6824  Vector<std::set<Node*> > segment_all_nodes_pt;
6825 
6826  // The number of segments in this processor
6827  const unsigned nsegments = segment_sorted_ele_pt.size();
6828 
6829 #ifdef PARANOID
6830  if (nnon_halo_face_elements > 0 && nsegments == 0)
6831  {
6832  std::ostringstream error_message;
6833  error_message
6834  << "The number of segments is zero, but the number of nonhalo\n"
6835  << "elements is: (" << nnon_halo_face_elements << ")\n";
6836  throw OomphLibError(error_message.str(),
6837  "TriangleMesh::re_scale_re_assigned_initial_zeta_values_for_internal_boundary()",
6838  OOMPH_EXCEPTION_LOCATION);
6839  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
6840 #endif
6841 
6842  // The arclength of each segment in the current processor
6843  Vector<double> segment_arclength(nsegments);
6844 
6845  // The initial zeta for the segment
6846  Vector<double> initial_zeta_segment(nsegments);
6847 
6848  // The final zeta for the segment
6849  Vector<double> final_zeta_segment(nsegments);
6850 
6851  // Go through all the segments and compute the LOCAL boundary
6852  // coordinates
6853  for (unsigned is = 0; is < nsegments; is++)
6854  {
6855 #ifdef PARANOID
6856  if (segment_sorted_ele_pt[is].size() == 0)
6857  {
6858  std::ostringstream error_message;
6859  error_message
6860  << "The (" << is << ")-th segment has no elements\n";
6861  throw OomphLibError(error_message.str(),
6862  "TriangleMesh::re_scale_re_assigned_initial_zeta_values_for_internal_boundary()",
6863  OOMPH_EXCEPTION_LOCATION);
6864  } // if (segment_sorted_ele_pt[is].size() == 0)
6865 #endif
6866 
6867  // Get access to the first element on the segment
6868  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
6869 
6870  // Number of nodes
6871  const unsigned nnod = first_ele_pt->nnode();
6872 
6873  // Get the first node of the current segment
6874  Node *first_node_pt = first_ele_pt->node_pt(0);
6875  if (is_inverted[first_ele_pt])
6876  {
6877  first_node_pt = first_ele_pt->node_pt(nnod-1);
6878  }
6879 
6880  // Get access to the last element on the segment
6881  FiniteElement* last_ele_pt = segment_sorted_ele_pt[is].back();
6882 
6883  // Get the last node of the current segment
6884  Node *last_node_pt = last_ele_pt->node_pt(nnod-1);
6885  if (is_inverted[last_ele_pt])
6886  {
6887  last_node_pt = last_ele_pt->node_pt(0);
6888  }
6889 
6890  // Coordinates of left node
6891  double x_left = first_node_pt->x(0);
6892  double y_left = first_node_pt->x(1);
6893 
6894  // Initialise boundary coordinate (local boundary coordinate for
6895  // boundaries with more than one segment)
6896  Vector<double> zeta(1, 0.0);
6897 
6898  // If we have associated a GeomObject then it is not necessary to
6899  // compute the arclength, only read the values from the nodes at
6900  // the edges
6901  if (this->boundary_geom_object_pt(b)!=0)
6902  {
6903  first_node_pt->get_coordinates_on_boundary(b, zeta);
6904  initial_zeta_segment[is] = zeta[0];
6905  last_node_pt->get_coordinates_on_boundary(b, zeta);
6906  final_zeta_segment[is] = zeta[0];
6907  }
6908 
6909  // Lexicographically bottom left node
6910  std::set<Node*> local_nodes_pt;
6911  local_nodes_pt.insert(first_node_pt);
6912 
6913  // Now loop over nodes in order
6914  for (std::list<FiniteElement*>::iterator it =
6915  segment_sorted_ele_pt[is].begin();
6916  it != segment_sorted_ele_pt[is].end(); it++)
6917  {
6918  // Get element
6919  FiniteElement* el_pt = *it;
6920 
6921  // Start node and increment
6922  unsigned k_nod = 1;
6923  int nod_diff = 1;
6924  if (is_inverted[el_pt])
6925  {
6926  k_nod = nnod - 2;
6927  nod_diff = -1;
6928  }
6929 
6930  // Loop over nodes
6931  for (unsigned j = 1; j < nnod; j++)
6932  {
6933  Node* nod_pt = el_pt->node_pt(k_nod);
6934  k_nod += nod_diff;
6935 
6936  // Coordinates of right node
6937  double x_right = nod_pt->x(0);
6938  double y_right = nod_pt->x(1);
6939 
6940  // Increment boundary coordinate
6941  zeta[0] += sqrt(
6942  (x_right - x_left) * (x_right - x_left) + (y_right - y_left)
6943  * (y_right - y_left));
6944 
6945  // Increment reference coordinate
6946  x_left = x_right;
6947  y_left = y_right;
6948 
6949  // Get lexicographically bottom left node but only
6950  // use vertex nodes as candidates
6951  local_nodes_pt.insert(nod_pt);
6952 
6953  } // for (j < nnod)
6954  } // iterator over the elements in the segment
6955 
6956  // Store the arclength of the segment
6957  segment_arclength[is] = zeta[0];
6958 
6959  // Add the nodes for the corresponding segment in the container
6960  segment_all_nodes_pt.push_back(local_nodes_pt);
6961 
6962  } // for (is < nsegments)
6963 
6964  // ------------------------------------------------------------------
6965  // Fourth: Now we have the segments sorted, with arclength and with
6966  // LOCAL arclength assigned to the nodes. Procced to re-scale the
6967  // coordinates on the nodes based on the arclength
6968  // ------------------------------------------------------------------
6969 
6970  // ------------------------------------------------------------------
6971  // Clear the original storages
6972  Boundary_segment_inverted[b].clear();
6973  Boundary_segment_initial_coordinate[b].clear();
6974  Boundary_segment_final_coordinate[b].clear();
6975 
6976  Boundary_segment_initial_zeta[b].clear();
6977  Boundary_segment_final_zeta[b].clear();
6978 
6979  Boundary_segment_initial_arclength[b].clear();
6980  Boundary_segment_final_arclength[b].clear();
6981 
6982  // Get the zeta values for the first and last node in the boundary
6983  Vector<double> first_node_zeta_coordinate(1,0.0);
6984  Vector<double> last_node_zeta_coordinate(1,0.0);
6985  first_node_zeta_coordinate = boundary_initial_zeta_coordinate(b);
6986  last_node_zeta_coordinate = boundary_final_zeta_coordinate(b);
6987 
6988  // Get the boundary arclength
6989  const double boundary_arclength =
6990  std::max(first_node_zeta_coordinate[0], last_node_zeta_coordinate[0]);
6991 
6992  // Go through the segments and get the first and last node for each
6993  // segment
6994  for (unsigned is = 0; is < nsegments; is++)
6995  {
6996  // Get the first face element of the segment
6997  FiniteElement* first_face_ele_pt = segment_sorted_ele_pt[is].front();
6998 
6999  // The number of nodes
7000  const unsigned nnod = first_face_ele_pt->nnode();
7001 
7002  // ... and the first node of the segment
7003  Node* first_node_pt = first_face_ele_pt->node_pt(0);
7004  if (is_inverted[first_face_ele_pt])
7005  {
7006  first_node_pt = first_face_ele_pt->node_pt(nnod-1);
7007  }
7008 
7009  // Get the bound coordinates of the node
7010  Vector<double> zeta_first(1);
7011  first_node_pt->get_coordinates_on_boundary(b, zeta_first);
7012 
7013  // Get the last face element of the segment
7014  FiniteElement* last_face_ele_pt = segment_sorted_ele_pt[is].back();
7015 
7016  // ... and the last node of the segment
7017  Node* last_node_pt = last_face_ele_pt->node_pt(nnod-1);
7018  if (is_inverted[last_face_ele_pt])
7019  {
7020  last_node_pt = last_face_ele_pt->node_pt(0);
7021  }
7022 
7023  // Get the bound coordinates of the node
7024  Vector<double> zeta_last(1);
7025  last_node_pt->get_coordinates_on_boundary(b, zeta_last);
7026 
7027  // Now that we have the first and last node of the segment, get
7028  // the coordinates of the nodes
7029  Vector<double> first_node_coord(2);
7030  Vector<double> last_node_coord(2);
7031  for (unsigned i = 0; i < 2; i++)
7032  {
7033  first_node_coord[i] = first_node_pt->x(i);
7034  last_node_coord[i] = last_node_pt->x(i);
7035  }
7036 
7037  // Re-assign the values to identify the segments on the new mesh
7038  Boundary_segment_inverted[b].push_back(0);
7039  Boundary_segment_initial_coordinate[b].push_back(first_node_coord);
7040  Boundary_segment_final_coordinate[b].push_back(last_node_coord);
7041 
7042  // Check if the boudary has an associated GeomObject
7043  if (this->boundary_geom_object_pt(b)!=0)
7044  {
7045  Boundary_segment_initial_zeta[b].push_back(zeta_first[0]);
7046  Boundary_segment_final_zeta[b].push_back(zeta_last[0]);
7047  }
7048  else
7049  {
7050  // Re-assign the values and re-scale them
7051  Boundary_segment_initial_arclength[b].push_back(
7052  zeta_first[0] * boundary_arclength);
7053  Boundary_segment_final_arclength[b].push_back(
7054  zeta_last[0] * boundary_arclength);
7055  }
7056 
7057  } // for (is < nsegments)
7058 
7059  // Clean all the created face elements
7060  for (unsigned i = 0; i < nele; i++)
7061  {
7062  delete face_el_pt[i];
7063  face_el_pt[i] = 0;
7064  }
7065 
7066  }
7067 
7068 #endif // OOMPH_HAS_MPI
7069 
7070 
7071 
7072 #ifdef OOMPH_HAS_TRIANGLE_LIB
7073 
7074  //========================================================================
7075  /// Create TriangulateIO object via the .poly file
7076  //========================================================================
7077  template <class ELEMENT>
7079  build_triangulateio(const std::string& poly_file_name,
7080  TriangulateIO& triangulate_io,
7081  bool &use_attributes)
7082  {
7083 
7084  // Process poly file
7085  // -----------------
7086  std::ifstream poly_file(poly_file_name.c_str(),std::ios_base::in);
7087  if(!poly_file)
7088  {
7089  throw OomphLibError("Error opening .poly file\n",
7090  OOMPH_CURRENT_FUNCTION,
7091  OOMPH_EXCEPTION_LOCATION);
7092  }
7093 
7094  // Initialize triangulateio structure
7095  TriangleHelper::initialise_triangulateio(triangulate_io);
7096 
7097  // Ignore the first line with structure description
7098  poly_file.ignore(80,'\n');
7099 
7100  // Read and store number of nodes
7101  unsigned invertices;
7102  poly_file>>invertices;
7103  triangulate_io.numberofpoints=invertices;
7104 
7105  // Initialisation of the point list
7106  triangulate_io.pointlist =
7107  (double *) malloc(triangulate_io.numberofpoints * 2 * sizeof(double));
7108 
7109  // Read and store spatial dimension of nodes
7110  unsigned mesh_dim;
7111  poly_file>>mesh_dim;
7112 
7113  if(mesh_dim == 0)
7114  {
7115  mesh_dim=2;
7116  }
7117 
7118 #ifdef PARANOID
7119  if(mesh_dim!=2)
7120  {
7121  throw OomphLibError("The dimension must be 2\n",
7122  OOMPH_CURRENT_FUNCTION,
7123  OOMPH_EXCEPTION_LOCATION);
7124  }
7125 #endif
7126 
7127  // Read and check the flag for attributes
7128  unsigned nextras;
7129  poly_file>> nextras;
7130 
7131  triangulate_io.numberofpointattributes = 0;
7132  triangulate_io.pointattributelist = (double *) NULL;
7133 
7134  // Read and check the flag for boundary markers
7135  unsigned nodemarkers;
7136  poly_file>>nodemarkers;
7137  triangulate_io.pointmarkerlist = (int *) NULL;
7138 
7139 #ifdef PARANOID
7140  // Reading the .poly with the oomph.lib we need
7141  // to set the point attribute and markers to 0
7142  if(nextras!=0 || nodemarkers!=0)
7143  {
7144  oomph_info << "===================================================="
7145  << std::endl<<std::endl;
7146  oomph_info <<"Reading the .poly file via oomph_lib \n"
7147  <<"point's attribute and point's markers \n"
7148  <<"are automatically set to 0"<<std::endl;
7149  oomph_info << "===================================================="
7150  <<std::endl;
7151  }
7152 #endif
7153 
7154  // Dummy for node number (and attribute or markers if included)
7155  unsigned dummy_value;
7156  unsigned count_point=0;
7157  std::string test_string;
7158 
7159  // Skip line with commentary
7160  getline(poly_file,test_string,'#');
7161  poly_file.ignore(80,'\n');
7162 
7163  // Read and store all the nodes coordinates
7164  // (hole's vertices as well)
7165  for(unsigned count=0;count<invertices;count++)
7166  {
7167  poly_file>>dummy_value;
7168  poly_file>>triangulate_io.pointlist[count_point];
7169  poly_file>>triangulate_io.pointlist[count_point+1];
7170  if(nextras!=0 || nodemarkers!=0)
7171  {
7172  for(unsigned j=0;j<nextras;j++)
7173  {
7174  poly_file>>dummy_value;
7175  }
7176  }
7177  else if(nextras!=0 && nodemarkers!=0)
7178  {
7179  for(unsigned j=0;j<nextras;j++)
7180  {
7181  poly_file>>dummy_value;
7182  poly_file>>dummy_value;
7183  }
7184  }
7185  // Read the next line
7186  poly_file.ignore(80,'\n');
7187 
7188  // Skip line with commentary for internal box whether found
7189  if(poly_file.get() == '#')
7190  {
7191  poly_file.ignore(80,'\n');
7192  }
7193  // If read the char should be put back in the string
7194 
7195  else
7196  {
7197  poly_file.unget();
7198  }
7199  count_point+=2;
7200  }
7201 
7202  // The line with the segment's commentary has been skipped
7203  // by the command of the last loop
7204 
7205  // Read and store the number of segments
7206  unsigned dummy_seg;
7207  unsigned inelements;
7208  poly_file>>inelements;
7209 
7210  unsigned segment_markers;
7211  poly_file>>segment_markers;
7212 
7213  // Marker list should be provided by the user to assign
7214  // each segment to a boundary
7215 #ifdef PARANOID
7216  if(segment_markers!=1)
7217  {
7218 
7219  std::ostringstream error_stream;
7220  error_stream
7221  <<"The segment marker should be provided \n"
7222  <<"In order to assign each segment to a boundary \n "<< std::endl;
7223 
7224  throw OomphLibError(error_stream.str(),
7225  OOMPH_CURRENT_FUNCTION,
7226  OOMPH_EXCEPTION_LOCATION);
7227  }
7228 #endif
7229 
7230  triangulate_io.numberofsegments = inelements;
7231  triangulate_io.segmentlist =
7232  (int *) malloc(triangulate_io.numberofsegments * 2 * sizeof(int));
7233  triangulate_io.segmentmarkerlist =
7234  (int *) malloc(triangulate_io.numberofsegments * sizeof(int));
7235 
7236  // Read all the segments edges and markers
7237  for(unsigned i=0;i<2*inelements;i+=2)
7238  {
7239  poly_file>>dummy_seg;
7240  poly_file>>triangulate_io.segmentlist[i];
7241  poly_file>>triangulate_io.segmentlist[i+1];
7242  if(segment_markers!=0)
7243  {
7244  poly_file>>triangulate_io.segmentmarkerlist[i/2];
7245  }
7246 
7247  //Skip line with commentary
7248  poly_file.ignore(80,'\n');
7249  }
7250 
7251  // Read and store the number of holes if given
7252  // Skip line with commentary
7253  if(getline(poly_file,test_string,'#'))
7254  {
7255  poly_file.ignore(80,'\n');
7256 
7257  unsigned dummy_hole;
7258  unsigned nhole;
7259  poly_file>>nhole;
7260 
7261  triangulate_io.numberofholes = nhole;
7262  triangulate_io.holelist =
7263  (double *) malloc(triangulate_io.numberofholes * 2 * sizeof(double));
7264 
7265  // Loop over the holes to get centre coords and store value onto the
7266  // TriangulateIO object
7267  for(unsigned i=0;i<2*nhole;i+=2)
7268  {
7269  poly_file>>dummy_hole;
7270  poly_file>>triangulate_io.holelist[i];
7271  poly_file>>triangulate_io.holelist[i+1];
7272  }
7273  }
7274 
7275  // Read and store the number of regions if given
7276  // Skip line with commentary
7277  if(getline(poly_file,test_string,'#'))
7278  {
7279  poly_file.ignore(80,'\n');
7280 
7281  unsigned dummy_region;
7282  unsigned nregion;
7283  poly_file>>nregion;
7284  std::cerr << "Regions: "<< nregion << std::endl;
7285  getchar();
7286 
7287  triangulate_io.numberofregions = nregion;
7288  triangulate_io.regionlist =
7289  (double *) malloc(triangulate_io.numberofregions * 4 * sizeof(double));
7290 
7291  // Check for using regions
7292  if (nregion > 0)
7293  {use_attributes=true;}
7294 
7295  // Loop over the regions to get coords and store value onto the
7296  // TriangulateIO object
7297  for(unsigned i=0;i<nregion;i++)
7298  {
7299  poly_file>>dummy_region;
7300  poly_file>>triangulate_io.regionlist[4*i];
7301  poly_file>>triangulate_io.regionlist[4*i+1];
7302  poly_file>>triangulate_io.regionlist[4*i+2];
7303  triangulate_io.regionlist[4*i+3] = 0.0;
7304  }
7305  }
7306 
7307  }
7308 
7309 #endif
7310 
7311 #ifdef OOMPH_HAS_TRIANGLE_LIB
7312 #ifdef OOMPH_HAS_MPI
7313 
7314  //======================================================================
7315  /// Used to dump info. related with distributed triangle meshes
7316  //======================================================================
7317  template<class ELEMENT>
7319  dump_distributed_info_for_restart(std::ostream &dump_file)
7320  {
7321  // First check that the mesh is distributed
7322  if (this->is_mesh_distributed())
7323  {
7324  // Save the original number of boundaries
7325  const unsigned nboundary = this->nboundary();
7326  dump_file << nboundary
7327  << " # number of original boundaries" << std::endl;
7328 
7329  // Save the number of shared boundaries
7330  const unsigned nshared_boundaries = this->nshared_boundaries();
7331  dump_file << nshared_boundaries
7332  << " # number of shared boundaries" << std::endl;
7333 
7334  // Save the initial and final shared boundaries ids
7335  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
7336  dump_file << init_shd_bnd_id
7337  << " # initial shared boundaries id" << std::endl;
7338 
7339  const unsigned final_shd_bnd_id = this->final_shared_boundary_id();
7340  dump_file << final_shd_bnd_id
7341  << " # final shared boundaries id" << std::endl;
7342 
7343  // Save the number of processors
7344  const unsigned nprocs = this->shared_boundaries_ids().size();
7345  dump_file << nprocs << " # number of processors" << std::endl;
7346 
7347  // Now save the processors ids and the shared boundary created
7348  // by them
7349  for (unsigned ip = 0; ip < nprocs; ip++)
7350  {
7351  for (unsigned jp = 0; jp < nprocs; jp++)
7352  {
7353  if (ip != jp)
7354  {
7355  // Get the number of shared boundaries with it these two
7356  // processors
7357  const unsigned nshared_boundaries_iproc_jproc =
7358  this->shared_boundaries_ids(ip, jp).size();
7359 
7360  // Save the number of shared boundaries with in these two
7361  // processors
7362  dump_file << nshared_boundaries_iproc_jproc
7363  << " # number of shared boundaries with in two "
7364  << "processors" << std::endl;
7365  for (unsigned is = 0; is < nshared_boundaries_iproc_jproc; is++)
7366  {
7367  const unsigned shared_boundary_id =
7368  this->shared_boundaries_ids(ip, jp, is);
7369  dump_file << ip << " " << jp << " " << shared_boundary_id
7370  << " # ip jp shared_boundary of processors ip and jp"
7371  << std::endl;
7372 
7373  } // for (is < nshared_boundaries_iproc_jproc)
7374  }
7375  } // for (jp < nprocs)
7376  } // for (ip < nprocs)
7377 
7378  // Now save the info. that states which shared boundary overlaps
7379  // an internal boundary
7380 
7381  // First check if there are shared boundaries overlapping internal
7382  // boundaries
7383  const unsigned nshared_boundaries_overlap_internal_boundaries =
7384  this->nshared_boundary_overlaps_internal_boundary();
7385  dump_file << nshared_boundaries_overlap_internal_boundaries
7386  << " # number of shared boundaries that overlap internal "
7387  << "boundaries" << std::endl;
7388 
7389  if (nshared_boundaries_overlap_internal_boundaries > 0)
7390  {
7391  for (unsigned isb = init_shd_bnd_id; isb < final_shd_bnd_id; isb++)
7392  {
7393  // Check if the current shared boundary overlaps an internal
7394  // boundary
7395  if (this->shared_boundary_overlaps_internal_boundary(isb))
7396  {
7397  // Which internal boundary is overlapped by the shared
7398  // boundary
7399  const unsigned overlapped_internal_boundary =
7400  shared_boundary_overlapping_internal_boundary(isb);
7401  // Save the shared boundary that overlaps the internal boundary
7402  dump_file << isb << " " << overlapped_internal_boundary
7403  << " # the shared boundary overlaps the internal "
7404  << "boundary " << std::endl;
7405 
7406  } // if (this->shared_boundary_overlaps_internal_boundary(isb))
7407  } // for (isb < final_shd_bnd_id)
7408  } // if (nshared_boundaries_overlap_internal_boundaries > 0)
7409 
7410  // Now save the info. related with the initial and final
7411  // boundary coordinates for each original boundary
7412 
7413  // Go through all the (original) boundaries to update the initial
7414  // and final boundary coordinates
7415  for (unsigned b = 0; b < nboundary; b++)
7416  {
7417  // Check if the boundary zeta coordinates for this boundary have
7418  // been already assigned, if that is the case then state the
7419  // flag to know that info. should be read
7420  if (Assigned_segments_initial_zeta_values[b])
7421  {
7422  // The boundary coordinates have been computed then state
7423  // the flag and save the info.
7424  dump_file << "1 # assigned boundary coordinates initial zeta values"
7425  << std::endl;
7426 
7427  // Save the initial and final boundary coordinates, same as
7428  // the initial and final zeta values for each boundary
7429 
7430  // First the vertices coordinates
7431  Vector<double> initial_coordinates=this->boundary_initial_coordinate(b);
7432 
7433  Vector<double> final_coordinates=this->boundary_final_coordinate(b);
7434 
7435  dump_file << std::setprecision(14)
7436  << initial_coordinates[0] << " " << initial_coordinates[1]
7437  << " # initial coordinates for the current boundary"
7438  << std::endl;
7439 
7440  dump_file << std::setprecision(14)
7441  << final_coordinates[0] << " " << final_coordinates[1]
7442  << " # final coordinates for the current boundary"
7443  << std::endl;
7444 
7445  // ... then the zeta values
7446 
7447 #ifdef PARANOID
7448  // Get the number of zeta coordinates (should be one)
7449  const unsigned zeta_size =
7450  this->boundary_initial_zeta_coordinate(b).size();
7451 
7452  if (zeta_size != 1)
7453  {
7454  std::ostringstream error_message;
7455  error_message
7456  <<"The dimension for the zeta values container is different\n"
7457  << "from 1, the current implementation only supports\n"
7458  << "one-dimensioned zeta containers\n\n";
7459  throw OomphLibError(error_message.str(),
7460  "TriangleMesh::dump_distributed_info_for_restart()",
7461  OOMPH_EXCEPTION_LOCATION);
7462  }
7463 #endif
7464 
7465  Vector<double> zeta_initial = this->boundary_initial_zeta_coordinate(b);
7466  Vector<double> zeta_final = this->boundary_final_zeta_coordinate(b);
7467 
7468  dump_file << std::setprecision(14)
7469  << zeta_initial[0]
7470  << " # initial zeta value for the current boundary"
7471  << std::endl;
7472 
7473  dump_file << std::setprecision(14)
7474  << zeta_final[0]
7475  << " # final zeta value for the current boundary"
7476  << std::endl;
7477 
7478  // Get the number of segments of the current boundary
7479  const unsigned nsegments = this->nboundary_segment(b);
7480  // Save the number of segments of the current boundary
7481  dump_file << b << " " << nsegments
7482  << " # of segments for the current boundary"
7483  << std::endl;
7484 
7485  // ... and then save that info for each segments
7486  for (unsigned is = 0; is < nsegments; is++)
7487  {
7488  // First the vertices coordinates
7489  Vector<double> initial_segment_coordinates =
7490  this->boundary_segment_initial_coordinate(b)[is];
7491  Vector<double> final_segment_coordinates =
7492  this->boundary_segment_final_coordinate(b)[is];
7493 
7494  dump_file << std::setprecision(14)
7495  << initial_segment_coordinates[0] << " "
7496  << initial_segment_coordinates[1]
7497  << " # initial segment coordinates for the current boundary"
7498  << std::endl;
7499 
7500  dump_file << std::setprecision(14)
7501  << final_segment_coordinates[0] << " "
7502  << final_segment_coordinates[1]
7503  << " # final segment coordinates for the current boundary"
7504  << std::endl;
7505 
7506  // ... then the zeta values
7507 
7508  if (this->boundary_geom_object_pt(b)!=0)
7509  {
7510  const double zeta_segment_initial =
7511  this->boundary_segment_initial_zeta(b)[is];
7512  const double zeta_segment_final =
7513  this->boundary_segment_final_zeta(b)[is];
7514 
7515  dump_file << std::setprecision(14)
7516  << zeta_segment_initial
7517  << " # initial segment zeta value for the current boundary"
7518  << std::endl;
7519 
7520  dump_file << std::setprecision(14)
7521  << zeta_segment_final
7522  << " # final segment zeta value for the current boundary"
7523  << std::endl;
7524  }
7525  else
7526  {
7527  const double arclength_segment_initial =
7528  this->boundary_segment_initial_arclength(b)[is];
7529  const double arclength_segment_final =
7530  this->boundary_segment_final_arclength(b)[is];
7531 
7532  dump_file << std::setprecision(14)
7533  << arclength_segment_initial
7534  << " # initial segment arclength for the current boundary"
7535  << std::endl;
7536 
7537  dump_file << std::setprecision(14)
7538  << arclength_segment_final
7539  << " # final segment arclength for the current boundary"
7540  << std::endl;
7541 
7542  } // else if (this->boundary_geom_object_pt(b)!=0)
7543 
7544  } // for (is < nsegments)
7545 
7546  } // if (Assigned_segments_initial_zeta_values[b])
7547  else
7548  {
7549  // The boundary coordinates have NOT been computed then state
7550  // the flag and save the info.
7551  dump_file << "0 # assigned boundary coordinates initial zeta values"
7552  << std::endl;
7553  }
7554 
7555  } // for (b < nboundary)
7556 
7557  } // if (this->is_mesh_distributed())
7558 
7559  }
7560 
7561  //======================================================================
7562  /// Used to read info. related with distributed triangle meshes
7563  //======================================================================
7564  template<class ELEMENT>
7566  read_distributed_info_for_restart(std::istream &restart_file)
7567  {
7568  // First check that the mesh is distributed
7569  if (this->is_mesh_distributed())
7570  {
7571  // Read the number of original boundaries
7572  const unsigned n_boundary = read_unsigned_line_helper(restart_file);
7573 
7574 #ifdef PARANOID
7575  if (n_boundary != this->nboundary())
7576  {
7577  std::ostringstream error_message;
7578  error_message
7579  << "The number of boundaries (" << n_boundary << ") on the "
7580  << "file used for restarting is different\nfrom the number of "
7581  << "boundaries ("<< this->nboundary() << ") on the current "
7582  << "mesh!!!\n\n\n";
7583  throw OomphLibError(error_message.str(),
7584  "TriangleMesh::read_distributed_info_for_restart()",
7585  OOMPH_EXCEPTION_LOCATION);
7586  }
7587 #endif
7588 
7589  // Read the number of shared boundaries
7590  unsigned n_shared_boundaries =
7591  read_unsigned_line_helper(restart_file);
7592  // We need to read the data because it comes in the file (add and
7593  // substract to avoid compilation warning)
7594  n_shared_boundaries++;
7595  n_shared_boundaries--;
7596 
7597  // Read the initial and final shared boundaries ids
7598  unsigned init_shd_bnd_id = read_unsigned_line_helper(restart_file);
7599  // We need to read the data because it comes in the file (add and
7600  // substract to avoid compilation warning)
7601  init_shd_bnd_id++;
7602  init_shd_bnd_id--;
7603  // Add and substract to avoid compilation warning
7604  unsigned final_shd_bnd_id = read_unsigned_line_helper(restart_file);
7605  // We need to read the data because it comes in the file (add and
7606  // substract to avoid compilation warning)
7607  final_shd_bnd_id++;
7608  final_shd_bnd_id--;
7609 
7610  // Read the number of processors involved in the generation of
7611  // mesh before restart
7612  const unsigned n_procs = read_unsigned_line_helper(restart_file);
7613 
7614 #ifdef PARANOID
7615  if (static_cast<int>(n_procs) != this->communicator_pt()->nproc())
7616  {
7617  std::ostringstream error_message;
7618  error_message
7619  << "The number of previously used processors ("<< n_procs
7620  << ") (read from the restart file) is different\nfrom the "
7621  << "number of current used processors ("
7622  << this->communicator_pt()->nproc() << ")\n\n";
7623  throw OomphLibError(error_message.str(),
7624  "TriangleMesh::read_distributed_info_for_restart()",
7625  OOMPH_EXCEPTION_LOCATION);
7626  }
7627 #endif
7628 
7629  // Clear all previuos info. related with shared boundaries
7630  this->shared_boundaries_ids().clear();
7631  this->shared_boundary_from_processors().clear();
7632  this->shared_boundary_overlaps_internal_boundary().clear();
7633 
7634  // Create the storage for the shared boundaries ids related with
7635  // the processors
7636  this->shared_boundaries_ids().resize(n_procs);
7637 
7638  // Now read the processors ids and the shared boundary created
7639  // by them
7640  for (unsigned ip = 0; ip < n_procs; ip++)
7641  {
7642  // Create the storage for the shared boundaries ids related with
7643  // the processors
7644  this->shared_boundaries_ids(ip).resize(n_procs);
7645  for (unsigned jp = 0; jp < n_procs; jp++)
7646  {
7647  if (ip != jp)
7648  {
7649  // Read the number of shared boundaries with in these two
7650  // processors
7651  const unsigned nshared_boundaries_iproc_jproc =
7652  read_unsigned_line_helper(restart_file);
7653  for (unsigned is = 0; is < nshared_boundaries_iproc_jproc; is++)
7654  {
7655  // Get the processors
7656  unsigned tmp_ip;
7657  restart_file >> tmp_ip;
7658  unsigned tmp_jp;
7659  restart_file >> tmp_jp;
7660 
7661  // Get the shared boundary id created by these two
7662  // processors
7663  const unsigned shared_boundary_id =
7664  read_unsigned_line_helper(restart_file);
7665 
7666  // Update the info. of the processors that give rise to
7667  // the shared boundaries
7668  this->shared_boundaries_ids(ip, jp).
7669  push_back(shared_boundary_id);
7670 
7671  // Update the structure that states the processors that
7672  // gave rise to the shared boundary
7673  Vector<unsigned> processors(2);
7674  processors[0] = ip;
7675  processors[1] = jp;
7676  this->shared_boundary_from_processors()[shared_boundary_id] =
7677  processors;
7678 
7679  } // for (is < nshared_boundaries_iproc_jproc)
7680  }
7681  } // for (jp < n_procs)
7682  } // for (ip < n_procs)
7683 
7684  // Now read the info. that states which shared boundary overlaps
7685  // an internal boundary
7686 
7687  // First check if there are shared boundaries overlapping internal
7688  // boundaries
7689  const unsigned nshared_boundaries_overlap_internal_boundaries =
7690  read_unsigned_line_helper(restart_file);
7691 
7692  for (unsigned isb = 0;
7693  isb < nshared_boundaries_overlap_internal_boundaries;
7694  isb++)
7695  {
7696  // Read the shared boundary that overlaps an internal boundary
7697  unsigned shared_boundary_overlapping;
7698  restart_file >> shared_boundary_overlapping;
7699  // ... and read the internal boundary that overlaps
7700  const unsigned overlapped_internal_boundary =
7701  read_unsigned_line_helper(restart_file);
7702 
7703  // Re-establish the info. of the shared boundaries overlapped
7704  // by internal boundaries
7705  this->shared_boundary_overlaps_internal_boundary()
7706  [shared_boundary_overlapping] = overlapped_internal_boundary;
7707  } // for (isb < nshared_boundaries_overlap_internal_boundaries)
7708 
7709  // Now read the info. related with the initial and final
7710  // boundary coordinates for each original boundary
7711 
7712  // Go through all the (original) boundaries to update the initial
7713  // and final boundary coordinates
7714  for (unsigned b = 0; b < n_boundary; b++)
7715  {
7716  // For each boundary check if the boundary coordinates initial
7717  // and final zeta vales were assigned in the restart file
7718  const unsigned boundary_coordinates_initial_zeta_values_assigned =
7719  read_unsigned_line_helper(restart_file);
7720 
7721  if (boundary_coordinates_initial_zeta_values_assigned)
7722  {
7723  // Clear any previous stored info. There should not be
7724  // info. already stored but better clear the info. for the
7725  // boundary
7726  Boundary_initial_coordinate[b].clear();
7727  Boundary_final_coordinate[b].clear();
7728 
7729  Boundary_initial_zeta_coordinate[b].clear();
7730  Boundary_final_zeta_coordinate[b].clear();
7731 
7732  // The info. for the segments
7733  Boundary_segment_inverted[b].clear();
7734  Boundary_segment_initial_coordinate[b].clear();
7735  Boundary_segment_final_coordinate[b].clear();
7736 
7737  Boundary_segment_initial_zeta[b].clear();
7738  Boundary_segment_final_zeta[b].clear();
7739 
7740  Boundary_segment_initial_arclength[b].clear();
7741  Boundary_segment_final_arclength[b].clear();
7742 
7743  // Read the initial and final boundary coordinates, same as
7744  // the initial and final zeta values for each boundary
7745 
7746  // First the vertices coordinates
7747  Vector<double> initial_coordinates(2);
7748 
7749  // Read the initial coordinates
7750  restart_file >> initial_coordinates[0] >> initial_coordinates[1];
7751 
7752  // Ignore rest of line
7753  restart_file.ignore(80,'\n');
7754 
7755  Vector<double> final_coordinates(2);
7756 
7757  // Read the final coordinates
7758  restart_file >> final_coordinates[0] >> final_coordinates[1];
7759 
7760  // Ignore rest of line
7761  restart_file.ignore(80,'\n');
7762 
7763  // Set the values in the containers
7764 
7765 
7766  this->boundary_initial_coordinate(b)=initial_coordinates;
7767  this->boundary_final_coordinate(b)=final_coordinates;
7768 
7769  // ... now read the zeta values
7770  Vector<double> zeta_initial(1);
7771  restart_file >> zeta_initial[0];
7772 
7773  // Ignore rest of line
7774  restart_file.ignore(80,'\n');
7775 
7776  Vector<double> zeta_final(1);
7777  restart_file >> zeta_final[0];
7778 
7779  // Ignore rest of line
7780  restart_file.ignore(80,'\n');
7781 
7782  // Set the values in the containers
7783  this->boundary_initial_zeta_coordinate(b) = zeta_initial;
7784  this->boundary_final_zeta_coordinate(b) = zeta_final;
7785 
7786  // Get the curent boundary id from the restart file
7787  unsigned current_boundary;
7788  restart_file >> current_boundary;
7789 
7790 #ifdef PARANOID
7791  if (current_boundary != b)
7792  {
7793  std::ostringstream error_message;
7794  error_message
7795  << "The current boundary id from the restart file ("
7796  << current_boundary << ") is different from\nthe boundary id "
7797  << b << "currently used to re-establish the initial and\nfinal "
7798  << "segment's zeta values\n\n";
7799  throw OomphLibError(error_message.str(),
7800  "TriangleMesh::read_distributed_info_for_restart()",
7801  OOMPH_EXCEPTION_LOCATION);
7802  }
7803 #endif
7804 
7805  // ... and its number of segments
7806  unsigned nsegments;
7807  restart_file >> nsegments;
7808 
7809  // Ignore rest of line
7810  restart_file.ignore(80,'\n');
7811 
7812  // Now read all the segments info.
7813 
7814  // ... and then save that info for each segments
7815  for (unsigned is = 0; is < nsegments; is++)
7816  {
7817  // First the vertices coordinates
7818  Vector<double> initial_segment_coordinates(2);
7819 
7820  // Read the initial coordinates
7821  restart_file >> initial_segment_coordinates[0]
7822  >> initial_segment_coordinates[1];
7823 
7824  // Ignore rest of line
7825  restart_file.ignore(80,'\n');
7826 
7827  Vector<double> final_segment_coordinates(2);
7828 
7829  // Read the final coordinates
7830  restart_file >> final_segment_coordinates[0]
7831  >> final_segment_coordinates[1];
7832 
7833  // Ignore rest of line
7834  restart_file.ignore(80,'\n');
7835 
7836  // Set the values in the containers
7837  this->boundary_segment_initial_coordinate(b).push_back(
7838  initial_segment_coordinates);
7839  this->boundary_segment_final_coordinate(b).push_back(
7840  final_segment_coordinates);
7841 
7842  // ... then the zeta values for the segment
7843  if (this->boundary_geom_object_pt(b)!=0)
7844  {
7845  Vector<double> zeta_segment_initial(1);
7846  restart_file >> zeta_segment_initial[0];
7847 
7848  // Ignore rest of line
7849  restart_file.ignore(80,'\n');
7850 
7851  Vector<double> zeta_segment_final(1);
7852  restart_file >> zeta_segment_final[0];
7853 
7854  // Ignore rest of line
7855  restart_file.ignore(80,'\n');
7856 
7857  // Set the values in the containers for the segment
7858  this->boundary_segment_initial_zeta(b).push_back(
7859  zeta_segment_initial[0]);
7860  this->boundary_segment_final_zeta(b).push_back(
7861  zeta_segment_final[0]);
7862  }
7863  else
7864  {
7865  Vector<double> arclength_segment_initial(1);
7866  restart_file >> arclength_segment_initial[0];
7867 
7868  // Ignore rest of line
7869  restart_file.ignore(80,'\n');
7870 
7871  Vector<double> arclength_segment_final(1);
7872  restart_file >> arclength_segment_final[0];
7873 
7874  // Ignore rest of line
7875  restart_file.ignore(80,'\n');
7876 
7877  // Set the values in the containers for the segment
7878  this->boundary_segment_initial_arclength(b).push_back(
7879  arclength_segment_initial[0]);
7880  this->boundary_segment_final_arclength(b).push_back(
7881  arclength_segment_final[0]);
7882  } // else if (this->boundary_geom_object_pt(b)!=0)
7883 
7884  } // for (is < nsegments)
7885 
7886  } // if (boundary_coordinates_initial_zeta_values_assigned)
7887 
7888  } // for (b < n_boundary)
7889 
7890  } // if (this->is_mesh_distributed())
7891 
7892  }
7893 
7894 #endif // #ifdef OOMPH_HAS_MPI
7895 #endif // #ifdef OOMPH_HAS_TRIANGLE_LIB
7896 
7897  //===================================================================
7898  // Output the nodes on the boundaries and their / respective boundary
7899  // coordinates(into separate tecplot / zones)
7900  //===================================================================
7901  template<class ELEMENT>
7903  std::ostream &outfile)
7904  {
7905  // First get all the elements adjacent to the given boundary, then
7906  // the face elements and extract the nodes on the boundaries using
7907  // the face elements. We can not use the data structure
7908  // Boundary_node_pt since the multi_domain functions add nodes there
7909  // without assigning the required boundary coordinate
7910 
7911  // Store the nodes in a set so we do not have repeated nodes
7912  std::set<Node*> boundary_nodes_pt;
7913  const unsigned n_boundary_ele = this->nboundary_element(b);
7914  for (unsigned e = 0; e < n_boundary_ele; e++)
7915  {
7916  // Get the boundary bulk element
7917  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
7918 #ifdef OOMPH_HAS_MPI
7919  // Only work with nonhalo elements if the mesh is distributed
7920  if (!bulk_ele_pt->is_halo())
7921  {
7922 #endif
7923  // Get the face index
7924  int face_index = this->face_index_at_boundary(b, e);
7925  // Create the face element
7926  FiniteElement* face_ele_pt = new DummyFaceElement<ELEMENT> (
7927  bulk_ele_pt, face_index);
7928 
7929  // Get the number of nodes on the face element
7930  const unsigned n_nodes = face_ele_pt->nnode();
7931  for (unsigned i = 0; i < n_nodes; i++)
7932  {
7933  // Get the nodes in the face elements
7934  Node* tmp_node_pt = face_ele_pt->node_pt(i);
7935  // Add the nodes to the set of boundary nodes
7936  boundary_nodes_pt.insert(tmp_node_pt);
7937  } // for (i < n_nodes)
7938 
7939  // Free the memory allocated for the face element
7940  delete face_ele_pt;
7941  face_ele_pt = 0;
7942 #ifdef OOMPH_HAS_MPI
7943  } // if (!bulk_ele_pt->is_halo())
7944 #endif
7945 
7946  } // for (e < n_boundary_ele)
7947 
7948  outfile << "ZONE T=\"Boundary nodes" << b << "\"\n";
7949  // Set to store the boundary nodes in order
7950  std::set<Vector<double> > set_node_coord;
7951  // Loop over the nodes on the boundary and store them in the set
7952  for (std::set<Node*>::iterator it = boundary_nodes_pt.begin();
7953  it != boundary_nodes_pt.end(); it++)
7954  {
7955  Node *inode_pt = (*it);
7956 
7957  // Get the node coordinates
7958  const unsigned n_dim = inode_pt->ndim();
7959  Vector<double> node_coord(n_dim+1);
7960 
7961  // Get the boundary coordinate
7962  Vector<double> zeta(1);
7963  inode_pt->get_coordinates_on_boundary(b, zeta);
7964  node_coord[0] = zeta[0];
7965  for (unsigned j = 0; j < n_dim; j++)
7966  {
7967  node_coord[j+1] = inode_pt->x(j);
7968  }
7969  set_node_coord.insert(node_coord);
7970  }
7971 
7972  for (std::set<Vector<double> >::iterator it = set_node_coord.begin();
7973  it != set_node_coord.end(); it++)
7974  {
7975  // Get the node coordinates
7976  Vector<double> node_coord = (*it);
7977 
7978  // Output the node coordinates
7979  const unsigned n_dim = node_coord.size()-1;
7980  for (unsigned j = 0; j < n_dim; j++)
7981  {
7982  outfile << node_coord[j+1] << " ";
7983  }
7984  // ... add an extra coordinate to avoid error with tecplot
7985  outfile << "0.0" << std::endl;
7986  }
7987 
7988  // ... loop again to plot the bound coordinates
7989  outfile << "ZONE T=\"Boundary coordinates " << b << "\"\n";
7990  for (std::set<Vector<double> >::iterator it = set_node_coord.begin();
7991  it != set_node_coord.end(); it++)
7992  {
7993  // Get the node coordinates
7994  Vector<double> node_coord = (*it);
7995 
7996  // Output the node coordinates
7997  const unsigned n_dim = node_coord.size()-1;
7998  for (unsigned j = 0; j < n_dim; j++)
7999  {
8000  outfile << node_coord[j+1] << " ";
8001  }
8002 
8003  // Output the boundary coordinate
8004  outfile << node_coord[0] << std::endl;
8005  }
8006 
8007  }
8008 
8009 #ifdef OOMPH_HAS_MPI
8010  //====================================================================
8011  // \short Creates the distributed domain representation. Joins the
8012  // original boundaires, shared boundaries and creates connections among
8013  // them to create the new polygons that represent the distributed
8014  // domain
8015  //====================================================================
8016  template<class ELEMENT>
8018  Vector<TriangleMeshPolygon *> &polygons_pt,
8019  Vector<TriangleMeshOpenCurve*> &open_curves_pt)
8020  {
8021  // Get the outer polygons, internal polygons, internal open curves
8022  // and join them with the shared polylines to create the distributed
8023  // domain representation (the new outer, internal polygons, and new
8024  // internal open curves)
8025 
8026  // Get the rank of the current processor
8027  const unsigned my_rank = this->communicator_pt()->my_rank();
8028 
8029  // *********************************************************************
8030  // Step (2) Get the outer, internal and shared boundaries to create the
8031  // new polygons
8032  // *********************************************************************
8033 
8034  // *********************************************************************
8035  // Step (2.1) Get the outer boundaries and check if it is necessary to use
8036  // a new representation (for example when the boundary was splitted in
8037  // the distribution process)
8038  // *********************************************************************
8039 
8040  // Storage for new created polylines, non sorted
8041  Vector<TriangleMeshPolyLine *> unsorted_outer_polyline_pt;
8042 
8043  // Storing for the polylines on the boundaries
8044  // The first index is for a set of connected polylines
8045  // The second index is for a polyline on a set of connected polylines
8046  Vector<Vector<TriangleMeshPolyLine *> > sorted_outer_curves_pt;
8047 
8048  // Copy the outer boundaries to the vector of polylines
8049  const unsigned nouter=this->Outer_boundary_pt.size();
8050  for (unsigned i = 0; i < nouter; i++)
8051  {
8052  const unsigned npolylines = this->Outer_boundary_pt[i]->npolyline();
8053  for (unsigned p = 0; p < npolylines; p++)
8054  {
8055  // Pointer to the current polyline
8056  TriangleMeshPolyLine *tmp_polyline_pt =
8057  this->Outer_boundary_pt[i]->polyline_pt(p);
8058  const unsigned nvertex = tmp_polyline_pt->nvertex();
8059  if (nvertex > 0)
8060  {
8061  // Get the boundary id of the polyline and check if that boundary
8062  // needs a new representation (for example when the boundary was
8063  // splitted in the distribution process)
8064  const unsigned bound_id = tmp_polyline_pt->boundary_id();
8065  if (!boundary_was_splitted(bound_id))
8066  {
8067  unsorted_outer_polyline_pt.push_back(tmp_polyline_pt);
8068  } // if (!boundary_was_splitted(bound_id))
8069  else
8070  {
8071  // Get the polylines that will represent this boundary
8072  Vector<TriangleMeshPolyLine*> tmp_vector_polylines =
8073  boundary_subpolylines(bound_id);
8074  const unsigned nsub_poly = tmp_vector_polylines.size();
8075 #ifdef PARANOID
8076  if (nsub_poly <= 1)
8077  {
8078  std::ostringstream error_message;
8079  error_message
8080  <<"The boundary ("<<bound_id<<") was marked to be splitted but\n"
8081  <<"there are only ("<<nsub_poly<<") polylines to represent it.\n";
8082  throw OomphLibError(error_message.str(),
8083  OOMPH_CURRENT_FUNCTION,
8084  OOMPH_EXCEPTION_LOCATION);
8085  }
8086 #endif
8087  // Add the new representation of the polylines (sub-polylines)
8088  // to represent this boundary
8089  for (unsigned isub = 0; isub < nsub_poly; isub++)
8090  {
8091  unsorted_outer_polyline_pt.push_back(tmp_vector_polylines[isub]);
8092 #ifdef PARANOID
8093  const unsigned nsvertex = tmp_vector_polylines[isub]->nvertex();
8094  if (nsvertex == 0)
8095  {
8096  std::ostringstream error_message;
8097  error_message
8098  << "The current chunk ("<< isub <<") of the polyline with\n"
8099  << "boundary id (" << bound_id << ") has no vertices\n";
8100  throw OomphLibError(error_message.str(),
8101  OOMPH_CURRENT_FUNCTION,
8102  OOMPH_EXCEPTION_LOCATION);
8103  } // if (nsvertex == 0)
8104 #endif // #ifdef PARANOID
8105  } // for (isub < nsub_poly)
8106  } // else if (!boundary_was_splitted(bound_id))
8107  } // if (nvertex > 0)
8108  } // for (p < npolylines)
8109  } // for (i < nouter)
8110 
8111  // Get the number of unsorted polylines
8112  unsigned nunsorted_outer_polyline = unsorted_outer_polyline_pt.size();
8113  if (nunsorted_outer_polyline > 0)
8114  {
8115 
8116  // Now that we have all the new unsorted polylines it is time to sort them
8117  // so they be all contiguous
8118  sort_polylines_helper(unsorted_outer_polyline_pt, sorted_outer_curves_pt);
8119 
8120  } // if (nunsorted_outer_polyline > 0)
8121 
8122  // *********************************************************************
8123  // Step (2.2) Get the internal closed boundaries and check if it is
8124  // necessary to use a new representation (for example when the boundary
8125  // was splitted in the distribution process)
8126  // *********************************************************************
8127 
8128  // Storage for new created polylines, non sorted
8129  Vector<TriangleMeshPolyLine *> unsorted_internal_closed_polyline_pt;
8130 
8131  // Storing for the polylines on the boundaries
8132  // The first index is for a set of connected polylines
8133  // The second index is for a polyline on a set of connected polylines
8134  Vector<Vector<TriangleMeshPolyLine *> > sorted_internal_closed_curves_pt;
8135 
8136  // Copy the internal closed boundaries to the vector of polylines
8137  const unsigned ninternal_closed=this->Internal_polygon_pt.size();
8138  for (unsigned i = 0; i < ninternal_closed; i++)
8139  {
8140  const unsigned npolylines = this->Internal_polygon_pt[i]->npolyline();
8141  for (unsigned p = 0; p < npolylines; p++)
8142  {
8143  // Pointer to the current polyline
8144  TriangleMeshPolyLine *tmp_polyline_pt =
8145  this->Internal_polygon_pt[i]->polyline_pt(p);
8146  const unsigned nvertex = tmp_polyline_pt->nvertex();
8147  if (nvertex > 0)
8148  {
8149  // Get the boundary id of the polyline and check if that boundary
8150  // needs a new representation (for example when the boundary was
8151  // splitted in the distribution process)
8152  const unsigned bound_id = tmp_polyline_pt->boundary_id();
8153  if (!boundary_was_splitted(bound_id))
8154  {
8155  unsorted_internal_closed_polyline_pt.push_back(tmp_polyline_pt);
8156  } // if (!boundary_was_splitted(bound_id))
8157  else
8158  {
8159  // Get the polylines that will represent this boundary
8160  Vector<TriangleMeshPolyLine*> tmp_vector_polylines =
8161  boundary_subpolylines(bound_id);
8162  const unsigned nsub_poly = tmp_vector_polylines.size();
8163 #ifdef PARANOID
8164  if (nsub_poly <= 1)
8165  {
8166  std::ostringstream error_message;
8167  error_message
8168  <<"The boundary ("<<bound_id<<") was marked to be splitted but\n"
8169  <<"there are only ("<<nsub_poly<<") polylines to represent it.\n";
8170  throw OomphLibError(error_message.str(),
8171  OOMPH_CURRENT_FUNCTION,
8172  OOMPH_EXCEPTION_LOCATION);
8173  }
8174 #endif
8175  // Add the new representation of the polylines (sub-polylines)
8176  // to represent this boundary
8177  for (unsigned isub = 0; isub < nsub_poly; isub++)
8178  {
8179  unsorted_internal_closed_polyline_pt.push_back(tmp_vector_polylines[isub]);
8180 #ifdef PARANOID
8181  const unsigned nsvertex = tmp_vector_polylines[isub]->nvertex();
8182  if (nsvertex == 0)
8183  {
8184  std::ostringstream error_message;
8185  error_message
8186  << "The current chunk ("<< isub <<") of the polyline with\n"
8187  << "boundary id (" << bound_id << ") has no vertices\n";
8188  throw OomphLibError(error_message.str(),
8189  OOMPH_CURRENT_FUNCTION,
8190  OOMPH_EXCEPTION_LOCATION);
8191  } // if (nsvertex == 0)
8192 #endif // #ifdef PARANOID
8193  } // for (isub < nsub_poly)
8194  } // else if (!boundary_was_splitted(bound_id))
8195  } // if (nvertex > 0)
8196  } // for (p < npolylines)
8197  } // for (i < ninternal_closed)
8198 
8199  const unsigned nunsorted_internal_closed_polyline =
8200  unsorted_internal_closed_polyline_pt.size();
8201 
8202  if (nunsorted_internal_closed_polyline > 0)
8203  {
8204  // Now that we have all the new unsorted polylines it is time to sort them
8205  // so they be all contiguous
8206  sort_polylines_helper(unsorted_internal_closed_polyline_pt,
8207  sorted_internal_closed_curves_pt);
8208  }
8209 
8210  // *********************************************************************
8211  // Step (2.3) Get the internal open boundaries and check if it is
8212  // necessary to use a new representation (for example when the boundary
8213  // was splitted in the distribution process)
8214  // *********************************************************************
8215 
8216  // Storage for new created polylines, non sorted
8217  Vector<TriangleMeshPolyLine *> unsorted_internal_open_polyline_pt;
8218 
8219  // Storing for the polylines on the boundaries
8220  // The first index is for a set of connected polylines
8221  // The second index is for a polyline on a set of connected polylines
8222  Vector<Vector<TriangleMeshPolyLine *> > sorted_internal_open_curves_pt;
8223 
8224  // Copy the internal open boundaries to the vector of polylines
8225  const unsigned ninternal_open = this->Internal_open_curve_pt.size();
8226  for (unsigned i = 0; i < ninternal_open; i++)
8227  {
8228  const unsigned ncurve_section =
8229  this->Internal_open_curve_pt[i]->ncurve_section();
8230  for (unsigned p = 0; p < ncurve_section; p++)
8231  {
8232  // Pointer to the current polyline
8233  TriangleMeshPolyLine *tmp_polyline_pt =
8234  this->Internal_open_curve_pt[i]->polyline_pt(p);
8235  const unsigned nvertex = tmp_polyline_pt->nvertex();
8236  if (nvertex > 0)
8237  {
8238  // Get the boundary id of the polyline and check if that boundary
8239  // needs a new representation (for example when the boundary was
8240  // splitted in the distribution process)
8241  const unsigned bound_id = tmp_polyline_pt->boundary_id();
8242  if (!boundary_was_splitted(bound_id))
8243  {
8244  // Only include as internal boundaries those not marked as
8245  // shared boundaries
8246  if (!boundary_marked_as_shared_boundary(bound_id, 0))
8247  {
8248  unsorted_internal_open_polyline_pt.push_back(tmp_polyline_pt);
8249  }
8250  } // if (!boundary_was_splitted(bound_id))
8251  else
8252  {
8253  // Get the polylines that will represent this boundary
8254  Vector<TriangleMeshPolyLine*> tmp_vector_polylines =
8255  boundary_subpolylines(bound_id);
8256  const unsigned nsub_poly = tmp_vector_polylines.size();
8257 #ifdef PARANOID
8258  if (nsub_poly <= 1)
8259  {
8260  std::ostringstream error_message;
8261  error_message
8262  <<"The boundary ("<<bound_id<<") was marked to be splitted but\n"
8263  <<"there are only ("<<nsub_poly<<") polylines to represent it.\n";
8264  throw OomphLibError(error_message.str(),
8265  OOMPH_CURRENT_FUNCTION,
8266  OOMPH_EXCEPTION_LOCATION);
8267  }
8268 #endif
8269  // Add the new representation of the polylines (sub-polylines)
8270  // to represent this boundary
8271  for (unsigned isub = 0; isub < nsub_poly; isub++)
8272  {
8273  // Only include as internal boundaries those not marked as
8274  // shared boundaries
8275  if (!boundary_marked_as_shared_boundary(bound_id, isub))
8276  {
8277  unsorted_internal_open_polyline_pt.push_back(tmp_vector_polylines[isub]);
8278  }
8279 #ifdef PARANOID
8280  const unsigned nsvertex = tmp_vector_polylines[isub]->nvertex();
8281  if (nsvertex == 0)
8282  {
8283  std::ostringstream error_message;
8284  error_message
8285  << "The current chunk ("<< isub <<") of the polyline with\n"
8286  << "boundary id (" << bound_id << ") has no vertices\n";
8287  throw OomphLibError(error_message.str(),
8288  OOMPH_CURRENT_FUNCTION,
8289  OOMPH_EXCEPTION_LOCATION);
8290  } // if (nsvertex == 0)
8291 #endif // #ifdef PARANOID
8292  } // for (isub < nsub_poly)
8293  } // else if (!boundary_was_splitted(bound_id))
8294  } // if (nvertex > 0)
8295  } // for (p < npolylines)
8296  } // for (i < ninternal_open)
8297 
8298  const unsigned nunsorted_internal_open_polyline =
8299  unsorted_internal_open_polyline_pt.size();
8300 
8301  if (nunsorted_internal_open_polyline > 0)
8302  {
8303  // Now that we have all the new unsorted polylines it is time to sort them
8304  // so they be all contiguous
8305  sort_polylines_helper(unsorted_internal_open_polyline_pt,
8306  sorted_internal_open_curves_pt);
8307  }
8308 
8309  // ********************************************************************
8310  // Step (2.4) Sort the polylines on the shared boundaries
8311  // ********************************************************************
8312 
8313  // Storage for new created polylines, non sorted
8314  Vector<TriangleMeshPolyLine *> unsorted_shared_polyline_pt;
8315 
8316  // Special storage for the shared polylines that will be also used
8317  // to connect with the internal boundaries
8318  Vector<TriangleMeshPolyLine *> unsorted_shared_to_internal_polyline_pt;
8319 
8320  // Storing for the polylines on the shared boundaries
8321  // The first index is for a set of connected polylines
8322  // The second index is for a polyline on a set of connected polylines
8323  Vector<Vector<TriangleMeshPolyLine *> > sorted_shared_curves_pt;
8324 
8325  // Copy the shared boudaries to the vector of polylines
8326  const unsigned ncurves = nshared_boundary_curves(my_rank);
8327  for (unsigned i = 0; i < ncurves; i++)
8328  {
8329  const unsigned npolylines = nshared_boundary_polyline(my_rank, i);
8330  for (unsigned p = 0; p < npolylines; p++)
8331  {
8332  const unsigned nvertex =
8333  shared_boundary_polyline_pt(my_rank, i, p)->nvertex();
8334  if (nvertex > 0)
8335  {
8336  TriangleMeshPolyLine *tmp_shared_poly_pt =
8337  shared_boundary_polyline_pt(my_rank, i, p);
8338 
8339  // First check if there are shared boundaries overlapping
8340  // internal boundaries
8341  if (this->nshared_boundary_overlaps_internal_boundary() > 0)
8342  {
8343  // Get the boundary id of the shared polyline
8344  const unsigned shd_bnd_id = tmp_shared_poly_pt->boundary_id();
8345  // If the shared polyline is marked as internal boundary
8346  // then include it in the special storage to look for
8347  // connection with internal boundaries
8348  if (this->shared_boundary_overlaps_internal_boundary(shd_bnd_id))
8349  {
8350  unsorted_shared_to_internal_polyline_pt.push_back(
8351  tmp_shared_poly_pt);
8352  }
8353  }
8354  unsorted_shared_polyline_pt.push_back(tmp_shared_poly_pt);
8355  }
8356  }
8357  }
8358 
8359  // Get the total number of shared polylines
8360  const unsigned nunsorted_shared_polyline =
8361  unsorted_shared_polyline_pt.size();
8362 
8363  if (nunsorted_shared_polyline > 0)
8364  {
8365  // Now that we have all the new unsorted polylines it is time to
8366  // sort them so they be all contiguous
8367  sort_polylines_helper(unsorted_shared_polyline_pt, sorted_shared_curves_pt);
8368  }
8369 
8370  // ********************************************************************
8371  // Step (3) Join the boundaries (shared, internal and outer to
8372  // create the new polygons)
8373  // ********************************************************************
8374 
8375  // Create the set of curves that will be used to create the new polygons
8376  // Get the total number of curves
8377  const unsigned nouter_curves = sorted_outer_curves_pt.size();
8378  const unsigned ninternal_closed_curves =
8379  sorted_internal_closed_curves_pt.size();
8380  const unsigned nshared_curves = sorted_shared_curves_pt.size();
8381  const unsigned ntotal_curves = nouter_curves +
8382  ninternal_closed_curves +
8383  nshared_curves;
8384 
8385  // Add all the polylines to a container
8386  unsigned counter = 0;
8387  Vector<Vector<TriangleMeshPolyLine *> > all_curves_pt(ntotal_curves);
8388 
8389  // Add the shared curves first, this ensure the generation of
8390  // internal polygons defined by the shared boundaries
8391  for (unsigned i = 0; i < nshared_curves; i++,counter++)
8392  {
8393  all_curves_pt[counter] = sorted_shared_curves_pt[i];
8394  }
8395 
8396  // Add the internal polygons (if any)
8397  for (unsigned i = 0; i < ninternal_closed_curves; i++,counter++)
8398  {
8399  all_curves_pt[counter] = sorted_internal_closed_curves_pt[i];
8400  }
8401 
8402  // Add the outer polygons
8403  for (unsigned i = 0; i < nouter_curves; i++,counter++)
8404  {
8405  all_curves_pt[counter] = sorted_outer_curves_pt[i];
8406  }
8407 
8408  // Create the temporary version of the domain by joining the new
8409  // polylines
8410  this->create_tmp_polygons_helper(all_curves_pt,polygons_pt);
8411  // Create the new open curves
8412  this->create_tmp_open_curves_helper(sorted_internal_open_curves_pt,
8413  unsorted_shared_to_internal_polyline_pt,
8414  open_curves_pt);
8415 
8416  // ********************************************************************
8417  // Step (4) Create connections among the outer boundaries
8418  // (intersections with themselves)
8419  // ********************************************************************
8420 
8421  // After creating the new boundaries representation (polylines)
8422  // establish the connections of the shared boundaries (with
8423  // themselves or with the original boundaries). This avoids the
8424  // multiple definition of vertices in the domain which cause
8425  // problems when calling Triangle
8426 
8427  this->create_shared_polylines_connections();
8428 
8429  // ------------------------------------------------------------------
8430  // Compute the new holes information. Those from the
8431  // extra_holes_coordinates container, and those from the original
8432  // closed boundaries. Add the holes created by the halo elements
8433  // adjacent to the shared boundaries
8434 
8435  // The storage for the new holes, get those from the
8436  // extra_holes_coordinates container and those from the internal
8437  // closed boundaries that are defined as holes
8438  Vector<Vector<double> > new_holes_coordinates;
8439 
8440  // Copy the holes (those defined by the original internal closed
8441  // boundaries and those in the extra holes container)
8442 
8443  // The holes defined by the original internal closed boundaries
8444  const unsigned n_holes = this->Internal_polygon_pt.size();
8445  for (unsigned h = 0; h < n_holes; h++)
8446  {
8447  Vector<double> hole_coordinates =
8448  this->Internal_polygon_pt[h]->internal_point();
8449  // If the closed boundary is a hole, then copy its hole
8450  if (!hole_coordinates.empty())
8451  {
8452  new_holes_coordinates.push_back(hole_coordinates);
8453  }
8454  } // for (h < n_holes)
8455 
8456  // Is this the first time we are going to copy the extra holes
8457  // coordinates
8458  if (First_time_compute_holes_left_by_halo_elements)
8459  {
8460  // The holes in the extra holes container
8461  const unsigned n_extra_holes = Extra_holes_coordinates.size();
8462  for (unsigned h = 0; h < n_extra_holes; h++)
8463  {
8464  Vector<double> hole_coordinates = Extra_holes_coordinates[h];
8465  new_holes_coordinates.push_back(hole_coordinates);
8466  } // for (h < n_extra_holes)
8467 
8468  // Copy the extra holes coordinates
8469  Original_extra_holes_coordinates = Extra_holes_coordinates;
8470 
8471  // Set the flag to false
8472  First_time_compute_holes_left_by_halo_elements = false;
8473 
8474  } // if (First_time_compute_holes_left_by_halo_elements)
8475  else
8476  {
8477  // Not the first time, then only copy the original extra holes
8478  // coordinates
8479  const unsigned n_original_extra_holes =
8480  Original_extra_holes_coordinates.size();
8481  for (unsigned h = 0; h < n_original_extra_holes; h++)
8482  {
8483  Vector<double> hole_coordinates = Original_extra_holes_coordinates[h];
8484  new_holes_coordinates.push_back(hole_coordinates);
8485  } // for (h < n_original_extra_holes)
8486  }
8487 
8488  // Add the holes created by the halo elements adjacent to the shared
8489  // boundaries
8490  compute_holes_left_by_halo_elements_helper(new_holes_coordinates);
8491 
8492  // Update the holes information, only use the coordinate inside the
8493  // poylgons that define the new domain
8494  update_holes_information_helper(polygons_pt, new_holes_coordinates);
8495 
8496  // tachidok Clear the storage by now
8497  //new_holes_coordinates.clear();
8498 
8499  // Now copy the info. in the extra holes coordinates container
8500  Extra_holes_coordinates = new_holes_coordinates;
8501 
8502  // Do not delete halo(ed) info., this will be "deleted"
8503  // automatically by not passing that information to the new adapted
8504  // mesh. Once the transfer of target areas is performed the halo(ed)
8505  // information is no longer required
8506 
8507  }
8508 
8509  //======================================================================
8510  // \short Take the polylines from the shared boundaries and the boundaries
8511  // to create polygons
8512  //======================================================================
8513  template<class ELEMENT>
8515  create_tmp_polygons_helper(Vector<Vector<TriangleMeshPolyLine *> >
8516  &polylines_pt,
8517  Vector<TriangleMeshPolygon *> &polygons_pt)
8518  {
8519  // Each vector of polylines (curve) is already sorted, it means that
8520  // all the polylines on the vector polylines_pt[i] point to the same
8521  // direction
8522 
8523  // --- Using this fact we should compare the first and last points from
8524  // these arrays of polylines (curves) and compare with the others
8525  // vectors of polylines (curves) end points
8526  // --- Once created a closed curve create a polygon
8527 
8528  // The number of curves
8529  const unsigned ncurves = polylines_pt.size();
8530 
8531  // The number of non sorted curves
8532  const unsigned nunsorted_curves = ncurves;
8533  // The number of sorted curves
8534  unsigned nsorted_curves = 0;
8535 
8536  // Vector to know which ncurve is already done
8537  std::vector<bool> done_curve(ncurves);
8538 
8539  do
8540  {
8541  // The list where to add the curves so that they be contiguous
8542  std::list<Vector<TriangleMeshPolyLine*> > list_building_polygon_pt;
8543 #ifdef PARANOID
8544  // Flag to indicate that a root curve was found
8545  bool root_curve_found = false;
8546 #endif
8547 
8548  // The index for the root_curve (we use it in further iterations as the
8549  // starting index so we dont need to search in already done curves)
8550  unsigned root_curve_idx = 0;
8551 
8552  // Get the root curve
8553  for (unsigned ic = 0; ic < ncurves; ic++)
8554  {
8555  if (!done_curve[ic])
8556  {
8557  root_curve_idx = ic;
8558  nsorted_curves++;
8559 #ifdef PARANOID
8560  root_curve_found = true;
8561 #endif
8562  done_curve[ic] = true;
8563  // ... break the loop
8564  break;
8565  }
8566  }
8567 
8568 #ifdef PARANOID
8569  if (!root_curve_found)
8570  {
8571  std::stringstream err;
8572  err <<"The root curve to create a polygon from the shared and "
8573  <<"original boundaries was not found!!!\n";
8574  throw OomphLibError(err.str(),
8575  "TriangleMesh::create_tmp_polygons_helper()",
8576  OOMPH_EXCEPTION_LOCATION);
8577  }
8578 #endif
8579 
8580  // Get the root curve
8581  Vector<TriangleMeshPolyLine*> root_curve_pt=polylines_pt[root_curve_idx];
8582 
8583  // Add the root curve to the list
8584  list_building_polygon_pt.push_back(root_curve_pt);
8585 
8586  // Get the initial and final vertices from the root curve
8587  Vector<double> root_curve_initial_vertex(2);
8588  Vector<double> root_curve_final_vertex(2);
8589 
8590  // We need to get the number of polylines that compose the root curve
8591  const unsigned nroot_curve_polyline = root_curve_pt.size();
8592  // ... and now get the initial and final vertex
8593  root_curve_pt[0]->initial_vertex_coordinate(root_curve_initial_vertex);
8594  root_curve_pt[nroot_curve_polyline-1]->
8595  final_vertex_coordinate(root_curve_final_vertex);
8596 
8597  // First check if it already create a polygon
8598  double diff =
8599  ((root_curve_initial_vertex[0] - root_curve_final_vertex[0])*
8600  (root_curve_initial_vertex[0] - root_curve_final_vertex[0]))
8601  +
8602  ((root_curve_initial_vertex[1] - root_curve_final_vertex[1])*
8603  (root_curve_initial_vertex[1] - root_curve_final_vertex[1]));
8604  diff = sqrt(diff);
8605  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8606  {
8607  // The polyline already create a Polygon, then create it!!!
8608  // Create the curve section representation of the current root curve
8609  Vector<TriangleMeshCurveSection*>
8610  curve_section_pt(nroot_curve_polyline);
8611 
8612  // Copy the polylines into its curve section representation
8613  for (unsigned i = 0; i < nroot_curve_polyline; i++)
8614  {curve_section_pt[i] = root_curve_pt[i];}
8615 
8616  // ... and create the Polygon
8617  TriangleMeshPolygon *new_polygon_pt =
8618  new TriangleMeshPolygon(curve_section_pt);
8619 
8620  // Mark the polygon for deletion (in the destructor)
8621  this->Free_polygon_pt.insert(new_polygon_pt);
8622 
8623  // Add the polygon to the output polygons
8624  polygons_pt.push_back(new_polygon_pt);
8625  } // (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8626  // when the curve creates a Polygon by itself
8627  else
8628  {
8629  // Flag to continue iterating while curves be added to the left
8630  // or right of the list of curves
8631  bool added_curve = false;
8632 #ifdef PARANOID
8633  // Flag to know if the "loop" finish because a polygon was
8634  // created or because no more curves can be added to the left or
8635  // right
8636  bool polygon_created = false;
8637 #endif
8638  do
8639  {
8640  added_curve = false;
8641  // If the root curve does not create a closed polygon then add curves
8642  // to the left or right until the curves create a closed polygon
8643  for (unsigned ic = root_curve_idx+1; ic < ncurves; ic++)
8644  {
8645  if (!done_curve[ic])
8646  {
8647  // Get the current curve
8648  Vector<TriangleMeshPolyLine*> current_curve_pt =
8649  polylines_pt[ic];
8650 
8651  // We need to get the number of polylines that compose the
8652  // current curve
8653  const unsigned ncurrent_curve_polyline = current_curve_pt.size();
8654 
8655  // ... and get the initial and final coordinates for the current
8656  // curve
8657  Vector<double> current_curve_initial_vertex(2);
8658  Vector<double> current_curve_final_vertex(2);
8659 
8660  current_curve_pt[0]->
8661  initial_vertex_coordinate(current_curve_initial_vertex);
8662  current_curve_pt[ncurrent_curve_polyline-1]->
8663  final_vertex_coordinate(current_curve_final_vertex);
8664 
8665  // ---------------------------------------------------------------
8666  // Start adding curves to the left or right
8667  // ---------------------------------------------------------------
8668  diff =
8669  ((current_curve_final_vertex[0] - root_curve_initial_vertex[0])*
8670  (current_curve_final_vertex[0] - root_curve_initial_vertex[0]))
8671  +
8672  ((current_curve_final_vertex[1] - root_curve_initial_vertex[1])*
8673  (current_curve_final_vertex[1] - root_curve_initial_vertex[1]));
8674  diff = sqrt(diff);
8675  // CURRENT curve to the LEFT of the ROOT curve
8676  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8677  {
8678  // Add the current curve to the left
8679  list_building_polygon_pt.push_front(current_curve_pt);
8680  // Mark the curve as done
8681  done_curve[ic] = true;
8682  // Update the initial vertex values
8683  root_curve_initial_vertex[0] = current_curve_initial_vertex[0];
8684  root_curve_initial_vertex[1] = current_curve_initial_vertex[1];
8685  // Increase the number of sorted curves
8686  nsorted_curves++;
8687  // Set the flag to indicate that a curve was added to the list
8688  added_curve = true;
8689  break;
8690  }
8691 
8692  diff =
8693  ((current_curve_initial_vertex[0] - root_curve_initial_vertex[0])*
8694  (current_curve_initial_vertex[0] - root_curve_initial_vertex[0]))
8695  +
8696  ((current_curve_initial_vertex[1] - root_curve_initial_vertex[1])*
8697  (current_curve_initial_vertex[1] - root_curve_initial_vertex[1]));
8698  diff = sqrt(diff);
8699  // CURRENT curve to the LEFT of the ROOT curve but INVERTED
8700  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8701  {
8702  Vector<TriangleMeshPolyLine*>
8703  tmp_curve_pt(ncurrent_curve_polyline);
8704  // Reverse each polyline and back them up
8705  for (unsigned it = 0; it < ncurrent_curve_polyline; it++)
8706  {
8707  current_curve_pt[it]->reverse();
8708  tmp_curve_pt[it] = current_curve_pt[it];
8709  }
8710  // Now copy them back but in reverse order
8711  unsigned count = 0;
8712  for (int i = ncurrent_curve_polyline - 1; i >= 0; i--,count++)
8713  {current_curve_pt[count] = tmp_curve_pt[i];}
8714  // Add the current curve to the left
8715  list_building_polygon_pt.push_front(current_curve_pt);
8716  // Mark the curve as done
8717  done_curve[ic] = true;
8718  // Update the initial vertex values
8719  root_curve_initial_vertex[0] = current_curve_final_vertex[0];
8720  root_curve_initial_vertex[1] = current_curve_final_vertex[1];
8721  // Increase the number of sorted curves
8722  nsorted_curves++;
8723  // Set the flag to indicate that a curve was added to the list
8724  added_curve = true;
8725  break;
8726  }
8727 
8728  diff =
8729  ((current_curve_initial_vertex[0] - root_curve_final_vertex[0])*
8730  (current_curve_initial_vertex[0] - root_curve_final_vertex[0]))
8731  +
8732  ((current_curve_initial_vertex[1] - root_curve_final_vertex[1])*
8733  (current_curve_initial_vertex[1] - root_curve_final_vertex[1]));
8734  diff = sqrt(diff);
8735  // CURRENT curve to the RIGHT of the ROOT curve
8736  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8737  {
8738  // Add the current curve to the right
8739  list_building_polygon_pt.push_back(current_curve_pt);
8740  // Mark the curve as done
8741  done_curve[ic] = true;
8742  // Update the initial vertex values
8743  root_curve_final_vertex[0] = current_curve_final_vertex[0];
8744  root_curve_final_vertex[1] = current_curve_final_vertex[1];
8745  // Increase the number of sorted curves
8746  nsorted_curves++;
8747  // Set the flag to indicate that a curve was added to the list
8748  added_curve = true;
8749  break;
8750  }
8751 
8752  diff =
8753  ((current_curve_final_vertex[0] - root_curve_final_vertex[0])*
8754  (current_curve_final_vertex[0] - root_curve_final_vertex[0]))
8755  +
8756  ((current_curve_final_vertex[1] - root_curve_final_vertex[1])*
8757  (current_curve_final_vertex[1] - root_curve_final_vertex[1]));
8758  diff = sqrt(diff);
8759  // CURRENT curve to the RIGHT of the ROOT curve but INVERTED
8760  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8761  {
8762  Vector<TriangleMeshPolyLine*>
8763  tmp_curve_pt(ncurrent_curve_polyline);
8764  // Reverse each polyline and back them up
8765  for (unsigned it = 0; it < ncurrent_curve_polyline; it++)
8766  {
8767  current_curve_pt[it]->reverse();
8768  tmp_curve_pt[it] = current_curve_pt[it];
8769  }
8770  // Now copy them back but in reverse order
8771  unsigned count = 0;
8772  for (int i = ncurrent_curve_polyline - 1; i >= 0; i--,count++)
8773  {current_curve_pt[count] = tmp_curve_pt[i];}
8774  // Add the current curve to the right
8775  list_building_polygon_pt.push_back(current_curve_pt);
8776  // Mark the curve as done
8777  done_curve[ic] = true;
8778  // Update the initial vertex values
8779  root_curve_final_vertex[0] = current_curve_initial_vertex[0];
8780  root_curve_final_vertex[1] = current_curve_initial_vertex[1];
8781  // Increase the number of sorted curves
8782  nsorted_curves++;
8783  // Set the flag to indicate that a curve was added to the list
8784  added_curve = true;
8785  break;
8786  }
8787 
8788  } // if (!done_curve[ic])
8789 
8790  } // for (ic < ncurves)
8791 
8792  // After adding a curve check if it is possible to create a polygon
8793  double diff =
8794  ((root_curve_initial_vertex[0] - root_curve_final_vertex[0])*
8795  (root_curve_initial_vertex[0] - root_curve_final_vertex[0]))
8796  +
8797  ((root_curve_initial_vertex[1] - root_curve_final_vertex[1])*
8798  (root_curve_initial_vertex[1] - root_curve_final_vertex[1]));
8799  diff = sqrt(diff);
8800  if (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8801  {
8802  // If the curves already create a Polygon then go out of the
8803  // loop and create the Polygon
8804  added_curve = false;
8805 #ifdef PARANOID
8806  // Set the flag to indicate that a Polygon has been created
8807  polygon_created = true;
8808 #endif
8809  } // (diff <
8810  // ToleranceForVertexMismatchInPolygons::Tolerable_error)
8811  // when the curve creates a Polygon by itself
8812 
8813  }while(added_curve);
8814 
8815 #ifdef PARANOID
8816  if (!polygon_created)
8817  {
8818  std::stringstream error_message;
8819  error_message
8820  << "It was no possible to create a TriangleMeshPolygon with "
8821  << "the input set of curves\n"
8822  << "These are the initial and final vertices in the current "
8823  << "sorted list of\nTriangleMeshPolyLines\n\n";
8824  Vector<double> init_vertex(2);
8825  Vector<double> final_vertex(2);
8826  unsigned icurve = 0;
8827  for (std::list<Vector<TriangleMeshPolyLine*> >::iterator it
8828  = list_building_polygon_pt.begin();
8829  it != list_building_polygon_pt.end(); it++, icurve++)
8830  {
8831  const unsigned ncurrent_curve_polyline = (*it).size();
8832  error_message
8833  << "TriangleMeshCurve #" << icurve << "\n"
8834  << "-----------------------------------\n";
8835  for (unsigned ip = 0; ip < ncurrent_curve_polyline; ip++)
8836  {
8837  Vector<double> init_vertex(2);
8838  Vector<double> final_vertex(2);
8839  (*it)[ip]->initial_vertex_coordinate(init_vertex);
8840  (*it)[ip]->final_vertex_coordinate(final_vertex);
8841  error_message
8842  <<"TriangleMeshPolyLine #" << ip << "\n"
8843  <<"Initial vertex: ("<<init_vertex[0]<<","<<init_vertex[1]<<")\n"
8844  <<"Final vertex: ("<<final_vertex[0]<<","<<final_vertex[1]<<")\n";
8845  } // for (ip < ncurrent_curve_polyline)
8846  } // for (it != list_building_polygon_pt.end())
8847 
8848  throw OomphLibError(error_message.str(),
8849  "TriangleMesh::create_tmp_polygons_helper()",
8850  OOMPH_EXCEPTION_LOCATION);
8851 
8852  } // if (!polygon_created)
8853 #endif
8854 
8855  // Create the polygon after joining the curves
8856  unsigned ntotal_polylines = 0;
8857  // Get the total number of polylines
8858  for (std::list<Vector<TriangleMeshPolyLine*> >::iterator it
8859  = list_building_polygon_pt.begin();
8860  it != list_building_polygon_pt.end(); it++)
8861  {
8862  ntotal_polylines+=(*it).size();
8863  }
8864 
8865  // Create the curve section representation of the curves on the list
8866  Vector<TriangleMeshCurveSection*> curve_section_pt(ntotal_polylines);
8867 
8868  // Copy the polylines into its curve section representation
8869  unsigned counter = 0;
8870  for (std::list<Vector<TriangleMeshPolyLine*> >::iterator it
8871  = list_building_polygon_pt.begin();
8872  it != list_building_polygon_pt.end(); it++)
8873  {
8874  const unsigned ncurrent_curve_polyline = (*it).size();
8875  for (unsigned ip = 0; ip < ncurrent_curve_polyline; ip++,counter++)
8876  {
8877  curve_section_pt[counter] = (*it)[ip];
8878  } // for (ip < ncurrent_curve_polyline)
8879  } // Loop over the list of polylines
8880 
8881  // ... and create the Polygon
8882  TriangleMeshPolygon *new_polygon_pt =
8883  new TriangleMeshPolygon(curve_section_pt);
8884 
8885  // Mark the polygon for deletion (in the destructor)
8886  this->Free_polygon_pt.insert(new_polygon_pt);
8887 
8888  // Add the polygon to the output polygons
8889  polygons_pt.push_back(new_polygon_pt);
8890 
8891  } // else
8892  // (diff < ToleranceForVertexMismatchInPolygons::Tolerable_error)
8893 
8894  }while(nsorted_curves < nunsorted_curves);
8895 
8896  }
8897 
8898  //======================================================================
8899  //\short Take the polylines from the original open curves and created
8900  //new temporaly representations of open curves with the bits of
8901  //original curves not overlapped by shared boundaries
8902  //======================================================================
8903  template<class ELEMENT>
8905  Vector<Vector<TriangleMeshPolyLine *> > &sorted_open_curves_pt,
8906  Vector<TriangleMeshPolyLine*> &unsorted_shared_to_internal_poly_pt,
8907  Vector<TriangleMeshOpenCurve *> &open_curves_pt)
8908  {
8909  // Here search for the connections of the open curves remaining as
8910  // open curves with the shared boundaries markes as internal
8911  const unsigned ninternal_open_curves = sorted_open_curves_pt.size();
8912 
8913  // Once identified the connections created with the new internal
8914  // boundaries representations add them to the open curves container
8915  for (unsigned i = 0; i < ninternal_open_curves; i++)
8916  {
8917  // Create the curve section representation of the polylines
8918  const unsigned npoly = sorted_open_curves_pt[i].size();
8919  Vector<TriangleMeshCurveSection*> tmp_curve_section(npoly);
8920  for (unsigned j = 0; j < npoly; j++)
8921  {
8922  tmp_curve_section[j] = sorted_open_curves_pt[i][j];
8923  }
8924  // ... and create the Open Curve
8925  TriangleMeshOpenCurve *new_open_curve_pt =
8926  new TriangleMeshOpenCurve(tmp_curve_section);
8927 
8928  // Mark the open curve for deletion (in the destructor)
8929  this->Free_open_curve_pt.insert(new_open_curve_pt);
8930 
8931  // Add the open curve to the output open curves
8932  open_curves_pt.push_back(new_open_curve_pt);
8933 
8934  } // (i < ninternal_open_curves)
8935 
8936  }
8937 
8938  //======================================================================
8939  //\short Check for any possible connections that the array of sorted
8940  //nodes have with original boundary nodes, previous shared polyline
8941  //nodes or with itself polyline nodes. In case that there is a
8942  //connection, get the boundary id to which connects
8943  //======================================================================
8944  template<class ELEMENT>
8946  std::set<FiniteElement*> &element_in_processor_pt,
8947  const int &root_edge_bnd_id,
8948  std::map<std::pair<Node*,Node*>, bool> &overlapped_face,
8949  std::map<unsigned, std::map<Node*, bool> >
8950  &node_on_bnd_not_overlapped_by_shd_bnd,
8951  std::list<Node*> &current_polyline_nodes,
8952  std::map<unsigned, std::list<Node*> >
8953  &shared_bnd_id_to_sorted_list_node_pt,
8954  const unsigned &node_degree,
8955  Node* &new_node_pt,
8956  const bool called_from_load_balance)
8957  {
8958  // Initialize the flag to return
8959  int flag_to_return = -1;
8960 
8961  // --------------------------------------------------------------------
8962  // First try to find a connection with any original boundary (keep
8963  // in mind the case when internal boundaries may be overlapped by
8964  // shared boundaries)
8965  // --------------------------------------------------------------------
8966 
8967  // Check if the shared boundary is overlapping an internal boundary
8968  bool overlapping_internal_boundary = false;
8969  // The boundary id overlapped by the current shared boundary
8970  unsigned internal_overlaping_bnd_id = 0;
8971  if (root_edge_bnd_id != -1)
8972  {
8973  // Set the flat to true
8974  overlapping_internal_boundary = true;
8975  // Set the bnd id of the overlapped internal boundary
8976  internal_overlaping_bnd_id = static_cast<unsigned>(root_edge_bnd_id);
8977  } // if (root_edge_bnd_id != -1)
8978 
8979  // ---------------------------------------------------------------
8980  // Check if the connection is with an original boundary by checking
8981  // if the new node is a boundary node, and it lives in an element
8982  // that is part of the domain
8983  // ---------------------------------------------------------------
8984  if (new_node_pt->is_on_boundary())
8985  {
8986  // Flag to indicate if the node lives in a non overlapped boundary
8987  bool is_node_living_in_non_overlapped_boundary = false;
8988 
8989  // If the node is a boundary node then check in which boundary it
8990  // is
8991  const unsigned noriginal_bnd = this->initial_shared_boundary_id();
8992  for (unsigned bb=0;bb<noriginal_bnd;bb++)
8993  {
8994  // If the shared boundary overlaps an internal boundary it will
8995  // be indicated by (root_edge_bnd_id != -1), the original
8996  // internal boundary that overlaps is given by the
8997  // root_edge_bnd_id value. We skip that original internal
8998  // boundary because the new node will be obviously ON the
8999  // internal boundary
9000  if (overlapping_internal_boundary)
9001  {
9002  // Is the node on boundary bb?
9003  if (new_node_pt->is_on_boundary(bb))
9004  {
9005  // If overlaping then check that the boundary is different
9006  // from the one that is being overlapped, or if overlapped
9007  // then check that the node is on an edge on the bb
9008  // boundary not overlapped by a shared boundary
9009  const bool on_bnd_edge_not_overlapped_by_shd_bnd =
9010  node_on_bnd_not_overlapped_by_shd_bnd[bb][new_node_pt];
9011  if (bb != internal_overlaping_bnd_id ||
9012  ((bb == internal_overlaping_bnd_id) &&
9013  (on_bnd_edge_not_overlapped_by_shd_bnd)))
9014  {
9015  // Is the node living in a non overlapped boundary
9016  if (bb != internal_overlaping_bnd_id)
9017  {
9018  is_node_living_in_non_overlapped_boundary = true;
9019  }
9020 
9021  // Now we need to check that the node lies on a boundary
9022  // that still exist (the elements associated to the
9023  // boundary may have been removed at the mesh distribution
9024  // stage). The node may be still marked as a boundary node
9025  // but the boundary may not have elements associated.
9026 
9027  // Get the number of elements in the boundary
9028  const unsigned n_bound_ele = this->nboundary_element(bb);
9029  if (n_bound_ele > 0)
9030  {
9031  // Check that node lies on a nonhalo element, those are
9032  // the elements used to update the domain representation
9033  for (unsigned e = 0; e < n_bound_ele; e++)
9034  {
9035  // Get the boundary bulk element
9036  FiniteElement* bulk_ele_pt = this->boundary_element_pt(bb, e);
9037  // Check if the element will be retained, it means it
9038  // is a nonhalo element
9039  std::set<FiniteElement*>::iterator it =
9040  element_in_processor_pt.find(bulk_ele_pt);
9041  // If found then check if the node live in the element
9042  if (it!=element_in_processor_pt.end())
9043  {
9044  // Found the node in the nonhalo face element
9045  bool found_node = false;
9046  // Get the face index
9047  int face_index = this->face_index_at_boundary(bb, e);
9048  // Create the face element
9049  FiniteElement* face_ele_pt =
9050  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
9051  // Get the number of nodes in the face element
9052  const unsigned n_node_face = face_ele_pt->nnode();
9053  // Get the first and last node of the face element
9054  Node* first_node_pt = face_ele_pt->node_pt(0);
9055  Node* last_node_pt = face_ele_pt->node_pt(n_node_face-1);
9056  // Create the edge with the pair of nodes
9057  std::pair<Node*, Node*> tmp_edge =
9058  std::make_pair(first_node_pt, last_node_pt);
9059  // Check if the face element edge is overlapped by a
9060  // shared boundary
9061  // Is the face not overlapped?
9062  if (!overlapped_face[tmp_edge])
9063  {
9064  // Look for the node in the current face element
9065  for (unsigned n = 0; n < n_node_face; n++)
9066  {
9067  // Check for every individual node
9068  if (face_ele_pt->node_pt(n) == new_node_pt)
9069  {
9070  found_node = true;
9071  break;
9072  } // if (face_ele_pt->node_pt(n) == new_node_pt)
9073  } // for (n < n_node_face)
9074  } // if (!overlapped_face[tmp_edge])
9075  // Free the memory of the face element
9076  delete face_ele_pt;
9077  if (found_node)
9078  {
9079  // return the first original boundary id found,
9080  // does not matter if the node lies on more than
9081  // one original boundary (with boundary
9082  // elements). This is the original boundary id
9083  // that will be used to create the connection
9084  flag_to_return = bb;
9085  return flag_to_return;
9086  } // if (found_node)
9087 
9088  } // if (it!=element_in_processor_pt.end())
9089 
9090  } // for (e < n_bound_ele)
9091 
9092  } // if (n_bound_ele > 0)
9093 
9094  } // if (bb != internal_overlaping_bnd_id ||
9095  // ((bb == internal_overlaping_bnd_id) &&
9096  // (on_bnd_edge_not_overlapped_by_shd_bnd)))
9097 
9098  } // if (nod_pt->is_on_boundary(bb))
9099 
9100  } // if (overlapping_internal_boundary)
9101  else
9102  {
9103  // Is the node on boundary bb?
9104  if (new_node_pt->is_on_boundary(bb))
9105  {
9106  // Now we need to check that the node lies on a boundary
9107  // that still exist (the elements associated to the boundary
9108  // may have been removed at the mesh distribution
9109  // stage). The node may be still marked as a boundary node
9110  // but the boundary may not have elements associated.
9111 
9112  // Get the number of elements in the boundary
9113  const unsigned n_bound_ele = this->nboundary_element(bb);
9114  if (n_bound_ele > 0)
9115  {
9116  // Check that node lies on a nonhalo element, those are
9117  // the elements used to update the domain representation
9118  for (unsigned e = 0; e < n_bound_ele; e++)
9119  {
9120  // Get the boundary bulk element
9121  FiniteElement* bulk_ele_pt = this->boundary_element_pt(bb, e);
9122  // Check if the element will be retained, it means it is
9123  // a nonhalo element
9124  std::set<FiniteElement*>::iterator it =
9125  element_in_processor_pt.find(bulk_ele_pt);
9126  // If found then check if the node live in the element
9127  if (it!=element_in_processor_pt.end())
9128  {
9129  // Found the node in the nonhalo face element
9130  bool found_node = false;
9131  // Get the face index
9132  int face_index = this->face_index_at_boundary(bb, e);
9133  // Create the face element
9134  FiniteElement* face_ele_pt =
9135  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
9136  // Get the number of nodes in the face element
9137  const unsigned n_node_face = face_ele_pt->nnode();
9138  // Get the first and last node of the face element
9139  Node* first_node_pt = face_ele_pt->node_pt(0);
9140  Node* last_node_pt = face_ele_pt->node_pt(n_node_face-1);
9141  // Create the edge with the pair of nodes
9142  std::pair<Node*, Node*> tmp_edge =
9143  std::make_pair(first_node_pt, last_node_pt);
9144  // Check if the face element edge is overlapped by a
9145  // shared boundary
9146  // Is the face not overlapped?
9147  if (!overlapped_face[tmp_edge])
9148  {
9149  // Look for the node in the current face element
9150  for (unsigned n = 0; n < n_node_face; n++)
9151  {
9152  // Check for every individual node
9153  if (face_ele_pt->node_pt(n) == new_node_pt)
9154  {
9155  found_node = true;
9156  break;
9157  } // if (face_ele_pt->node_pt(n) == new_node_pt)
9158  } // for (n < n_node_face)
9159  } // if (!overlapped_face[tmp_edge])
9160  // Free the memory of the face element
9161  delete face_ele_pt;
9162  if (found_node)
9163  {
9164  // return the first original boundary id found, does
9165  // not matter if the node lies on more than one
9166  // original boundary (with boundary elements). This
9167  // is the original boundary id that will be used to
9168  // create the connection
9169  flag_to_return = bb;
9170  return flag_to_return;
9171  } // if (found_node)
9172 
9173  } // if (it!=element_in_processor_pt.end())
9174 
9175  } // for (e < n_bound_ele)
9176 
9177  } // if (n_bound_ele > 0)
9178 
9179  } // if (nod_pt->is_on_boundary(bb))
9180  } // else if (overlapping_internal_boundary)
9181  } // for (bb < noriginal_bnd)
9182 
9183  // We will only reach this stage when the node was found to be
9184  // connected to an original boundary but the element(s) on that
9185  // boundary where the node should live are not part of the domain.
9186  // Think in a corner of a triangle which touches the boundary
9187  // which elements will not be part of the domain
9188 
9189  // We need to break the currently forming polyline
9190  //flag_to_return = -3;
9191 
9192  // We need to break the currently forming polyline if and only if
9193  // the boundary(ies) in which the node is living is(are) not an
9194  // overlapped boundary
9195  if (!overlapping_internal_boundary)
9196  {
9197  // If the boundary(ies) in which the node is living is(are) an
9198  // overlapped boundary then break the break the formation of the
9199  // polyline
9200  flag_to_return = -3;
9201  }
9202  else
9203  {
9204  // The boundary is overlapped, if the node lives in a non
9205  // overlapped boundary then we can break the formation of the
9206  // polyline
9207  if (is_node_living_in_non_overlapped_boundary)
9208  {
9209  flag_to_return = -3;
9210  } // if (is_node_living_in_non_overlapped_boundar)y
9211 
9212  } // if (!overlapping_internal_boundary)
9213 
9214  } // if (new_node_pt->is_on_boundary())
9215 
9216  // Return inmediately if the connection is with an original boundary
9217  // whose elements are still part of the domain
9218  if (flag_to_return >= 0)
9219  {
9220  return flag_to_return;
9221  }
9222 
9223  // ----------------------------------------------------------------------
9224  // Secondly, if there is not a connection with any original
9225  // boundary, or if there is connection but with an original boundary
9226  // whose elements are not part of the domain, then check for
9227  // connections with previously created shared polylines
9228  // ----------------------------------------------------------------------
9229  // Store all the previous shared polylines to which the current
9230  // found is found to be connected
9231  Vector<unsigned> candidate_shared_bnd_to_connect;
9232  // Check for all the previous polylines except the current one
9233  for (std::map<unsigned, std::list<Node*> >::iterator it =
9234  shared_bnd_id_to_sorted_list_node_pt.begin();
9235  it != shared_bnd_id_to_sorted_list_node_pt.end();
9236  it++)
9237  {
9238  // Get the boundary id of the list of nodes that created the
9239  // polyline (the shared boundary id associated with the list of
9240  // nodes)
9241  const unsigned i_bnd_id = (*it).first;
9242  // Get an iterator pointer to the list of nodes of the shared
9243  // polyline
9244  std::list<Node*>::iterator it_list = (*it).second.begin();
9245  // Get the total number of nodes associated to the boundary
9246  const unsigned n_nodes = (*it).second.size();
9247  // Search for connections in the list of nodes
9248  for (unsigned i = 0; i < n_nodes; i++, it_list++)
9249  {
9250  // Is the node already part of any other shared boundary
9251  if ((*it_list) == new_node_pt)
9252  {
9253  // Include the i-th boundary id in the list of candidate
9254  // shared boundaries to connect
9255  candidate_shared_bnd_to_connect.push_back(i_bnd_id);
9256  // Break the look with the i-th shared boundary, check with
9257  // the others shared boundaries
9258  break;
9259  } // if ((*it_list) == new_node_pt)
9260 
9261  } // for (i < nnodes)
9262 
9263  } // Loop over the shared boundaries and associated nodes
9264 
9265  // Get the number of candidate shared boundaries to connect
9266  const unsigned n_candidate_shared_bnd_to_connect =
9267  candidate_shared_bnd_to_connect.size();
9268 
9269  // Is there a connection with any previous shared polyline
9270  if (n_candidate_shared_bnd_to_connect > 0)
9271  {
9272  // If called from load balance we do not need to check if the
9273  // shared boundary is part of the processor since it certanily is,
9274  // only the shared boundaries that are pare of the processor are
9275  // used to created connection when creating the new shared
9276  // boundaries in the load balance rutine
9277  if (called_from_load_balance)
9278  {
9279  return candidate_shared_bnd_to_connect[0];
9280  }
9281 
9282  // We need to ensure that the shared boundary to which we are
9283  // connecting is part of the current processor, if none of the
9284  // found shared bundaries is in the current processor then return
9285  // the flag for "connection with boundary not in the current
9286  // processor"
9287 
9288  // Store the shared boundaries associated with the current processor
9289  Vector<unsigned> shared_bound_in_this_proc;
9290 
9291  // Get the shared boundaries associated with the current processor
9292  shared_boundaries_in_this_processor(shared_bound_in_this_proc);
9293 
9294  // If any of the candidate shared boundaries to connect is in the
9295  // current processor then return that shared boundary id
9296 
9297  // The number of shared boundaries in the current processor
9298  const unsigned n_shared_bound_in_this_proc =
9299  shared_bound_in_this_proc.size();
9300 
9301  // Loop over the candidate shared boundaries to connect
9302  for (unsigned i = 0; i < n_candidate_shared_bnd_to_connect; i++)
9303  {
9304  // Get the i-th candidate shared boundary to connect
9305  const unsigned i_candidate_shared_bnd =
9306  candidate_shared_bnd_to_connect[i];
9307 
9308  // Loop over the shared boundaries in the current processor
9309  for (unsigned j = 0; j < n_shared_bound_in_this_proc; j++)
9310  {
9311  // Is the candidate boundary a shared boundary in this processor?
9312  if (i_candidate_shared_bnd == shared_bound_in_this_proc[j])
9313  {
9314  // Return the candidate shared boundary
9315  flag_to_return = i_candidate_shared_bnd;
9316  return flag_to_return;
9317  } // The candidate shared boundary is a boundary in the
9318  // current processor
9319 
9320  } // for (j < n_shared_bound_in_this_proc)
9321 
9322  } // for (i < n_candidate_shared_bnd_to_connect)
9323 
9324  // If non of the candidate shared boundaries to connect is in the
9325  // current processor the mark that we need to stop the addition of
9326  // vertices at this side of the polyline
9327  flag_to_return = -3;
9328 
9329  } // if (n_candidate_shared_bnd_to_connect > 0)
9330 
9331  // Return inmediately if the connection is with a previuos shared
9332  // boundary
9333  if (flag_to_return >= 0)
9334  {
9335  return flag_to_return;
9336  }
9337 
9338  // ------------------------------------------------------------------
9339  // Finally,check for connections with the same polyline (the shared
9340  // boundary that is being constructed). We are trying to avoid loops
9341  // or connections with the same shared boundary that is why this is
9342  // checked at the end
9343  // ------------------------------------------------------------------
9344  unsigned nrepeated = 0;
9345  for (std::list<Node*>::iterator it_list = current_polyline_nodes.begin();
9346  it_list != current_polyline_nodes.end();
9347  it_list++)
9348  {
9349  // There must be at least one repeated node (the one that we have
9350  // just added, and it should be the first or last node)
9351  if ((*it_list) == new_node_pt) {nrepeated++;}
9352  }
9353  // If the number of repeated nodes is greater than one then the
9354  // polyline has a connection with itself
9355  if (nrepeated > 1)
9356  {
9357  // Return the flag value to indicate connection with itself, we
9358  // can not return the boundary id of the current polyline since it
9359  // has not been already assigned
9360  flag_to_return = -2;
9361  }
9362 
9363  // If there is no connection at all check the degree of the node, if
9364  // it is greater than 2 then return the flag to stop adding nodes
9365  // after this one
9366  if (node_degree > 2)
9367  {
9368  flag_to_return = -3;
9369  }
9370 
9371  // Return the flag
9372  return flag_to_return;
9373 
9374  }
9375 
9376  //======================================================================
9377  // \short Establish the connections of the polylines previously
9378  // marked as having connections. This connections were created in the
9379  // function TriangleMesh::create_polylines_from_halo_elements_helper().
9380  // In case of doing load balancing the connections were created by the
9381  // function RefineableTriangleMesh::create_new_shared_boundaries()
9382  // ======================================================================
9383  template<class ELEMENT>
9385  {
9386  // Get the rank of the current processor
9387  const unsigned my_rank = this->communicator_pt()->my_rank();
9388 
9389  // Get the shared curves associated with this processor
9390  Vector<Vector<TriangleMeshPolyLine*> > shared_curves_pt =
9391  this->Shared_boundary_polyline_pt[my_rank];
9392 
9393  // Loop through the shared boundaries on the current processor and
9394  // check if they are marked to create a connection
9395  const unsigned ncurves = shared_curves_pt.size();
9396  for (unsigned icurve = 0; icurve < ncurves; icurve++)
9397  {
9398  // Get the number of polylines in the current shared curve
9399  const unsigned npoly = shared_curves_pt[icurve].size();
9400  for (unsigned ipoly = 0; ipoly < npoly; ipoly++)
9401  {
9402  // Get the polyline representation of the shared boundary
9403  TriangleMeshPolyLine *shd_poly_pt = shared_curves_pt[icurve][ipoly];
9404 
9405  // Get the boundary id of the current polyline
9406  const unsigned bound_id = shd_poly_pt->boundary_id();
9407 
9408  // Is the left vertex connected
9409  const bool is_connected_to_the_left =
9410  shd_poly_pt->is_initial_vertex_connected();
9411 
9412  // Is the right vertex connected
9413  const bool is_connected_to_the_right =
9414  shd_poly_pt->is_final_vertex_connected();
9415 
9416  // -----------------------------------------------------------------
9417  // If there is a connection at one of the ends we need to
9418  // establish that connection
9419  if (is_connected_to_the_left || is_connected_to_the_right)
9420  {
9421  // Now get the new left and right vertices of the shared
9422  // polyline
9423  const unsigned n_vertex = shd_poly_pt->nvertex();
9424 
9425  // Now get the polylines to where the current shared boundary is
9426  // connected and create the connections
9427 
9428  // --------------------------------------------------------------
9429  // Connection to the left
9430  if (is_connected_to_the_left)
9431  {
9432  // Get the unsigned version of the bound id to connect to
9433  // the left
9434  const unsigned uconnection_to_the_left =
9435  shd_poly_pt->initial_vertex_connected_bnd_id();
9436 
9437  // The pointer to the boundary to connect
9438  TriangleMeshPolyLine *poly_to_connect_pt = 0;
9439 
9440  // Flag to indicate we are trying to connect to an split
9441  // boundary
9442  bool connecting_to_an_split_boundary = false;
9443 
9444  // Flag to indicate we are trying to connecto to an internal
9445  // boundary that is overlaped by a shared boundary
9446  bool connecting_to_an_overlaped_boundary = false;
9447 
9448  // Check if the connection is with itself
9449  if (uconnection_to_the_left == bound_id)
9450  {
9451  // Set the pointer to the polyline to connect
9452  poly_to_connect_pt = shd_poly_pt;
9453  }
9454  else
9455  {
9456  // Get the initial shared boundary ids
9457  const unsigned initial_shd_bnd_id = initial_shared_boundary_id();
9458  // Check if the boundary to connect is a shared polyline
9459  if (uconnection_to_the_left >= initial_shd_bnd_id)
9460  {
9461  // Get the polyline pointer representing the destination
9462  // boundary
9463  poly_to_connect_pt =
9464  boundary_polyline_pt(uconnection_to_the_left);
9465  } // if (uconnection_to_the_left >= initial_shd_bnd_id)
9466  else
9467  {
9468  // If we are going to connect to an original boundary
9469  // verify if the boundary was splitted during the
9470  // distribution process to consider all the chunks
9471  // (sub-polylines) of the boundary
9472  if (boundary_was_splitted(uconnection_to_the_left))
9473  {
9474  connecting_to_an_split_boundary = true;
9475  } // if (boundary_was_splitted(uconnection_to_the_left))
9476 
9477  // If we are going to connect to an original boundary
9478  // verify if the boundary, or any of its chunks is
9479  // marked to be overlapped by a shared boundary, if that
9480  // is the case we first check for connections in the
9481  // shared boundary that overlaps the internal boundary,
9482  // or the chunks, and then check for connections in the
9483  // original boundary
9484  if (connecting_to_an_split_boundary)
9485  {
9486  // Get the number of chucks that represent the
9487  // destination boundary
9488  const unsigned n_sub_poly =
9489  nboundary_subpolylines(uconnection_to_the_left);
9490  // Now loop over the chunks of the destination
9491  // boundary and if any of them is marked to be
9492  // overlaped by a shared boundary then set the flag
9493  // and break the loop
9494  for (unsigned ii =0; ii < n_sub_poly; ii++)
9495  {
9496  if (boundary_marked_as_shared_boundary(
9497  uconnection_to_the_left, ii))
9498  {
9499  // Mark the boundary as being overlaped by a
9500  // shared boundary
9501  connecting_to_an_overlaped_boundary = true;
9502  // Break, no need to look for more overlapings
9503  break;
9504  } // if (boundary_marked_as_shared_boundary(...))
9505  } // for (ii < n_sub_poly)
9506  } // if (connecting_to_an_split_boundary)
9507  else
9508  {
9509  // If not connecting to an split boundary then check
9510  // if the whole destination boundary is overlaped by
9511  // an internal boundary
9512  if (boundary_marked_as_shared_boundary(
9513  uconnection_to_the_left, 0))
9514  {
9515  // Mark the boundary as being overlaped by a shared
9516  // boundary
9517  connecting_to_an_overlaped_boundary = true;
9518  } // if (boundary_marked_as_shared_boundary(...))
9519  } // else if (connecting_to_an_split_boundary)
9520 
9521  // If we are connecting neither to an split boundary nor
9522  // an overlaped boundary then get the pointer to the
9523  // original boundary
9524  if (!(connecting_to_an_split_boundary ||
9525  connecting_to_an_overlaped_boundary))
9526  {
9527  // Get the polyline pointer representing the
9528  // destination boundary
9529  poly_to_connect_pt =
9530  boundary_polyline_pt(uconnection_to_the_left);
9531  } // else if (NOT split, NOT overlaped)
9532  } // else if (uconnection_to_the_left >= initial_shd_bnd_id)
9533 
9534  } // else if (uconnection_to_the_left == bound_id)
9535 
9536 #ifdef PARANOID
9537  // If we are not connecting to an original boundary
9538  // (connecting to the same shared boundary or to another
9539  // shared boundary) then the boundary should not be marked
9540  // as split
9541  if (!connecting_to_an_split_boundary)
9542  {
9543  if (boundary_was_splitted(uconnection_to_the_left))
9544  {
9545  std::stringstream error;
9546  error
9547  << "The current shared boundary (" << bound_id << ") was "
9548  << "marked to have a connection\nto the left with the "
9549  << "boundary (" << uconnection_to_the_left << ").\n"
9550  << "The problem is that the destination boundary (possibly\n"
9551  << "another shared boundary) is marked to be split\n"
9552  << "There should not be split shared boundaries\n\n";
9553  throw OomphLibError(
9554  error.str(),
9555  "TriangleMesh::create_shared_polylines_connections()",
9556  OOMPH_EXCEPTION_LOCATION);
9557  }
9558  } // if (!connecting_to_an_split_boundary)
9559 #endif
9560 
9561  // Now look for the vertex number on the destination
9562  // boundary(ies) -- in case that the boundary was split ---
9563 
9564  // Do not check for same orientation, that was previously
9565  // worked by interchanging the connections boundaries (if
9566  // necessary)
9567 
9568  // Get the left vertex in the shared boundary
9569  Vector<double> shd_bnd_left_vertex =
9570  shd_poly_pt->vertex_coordinate(0);
9571 
9572  // If the boundary was not split then ...
9573  if (!connecting_to_an_split_boundary)
9574  {
9575  // ... check if the boundary is marked to be overlaped by
9576  // a shared boundary
9577  if (!connecting_to_an_overlaped_boundary)
9578  {
9579  // If that is not the case then we can safely look for
9580  // the vertex number on the destination boundar
9581  unsigned vertex_index = 0;
9582 
9583  const bool found_vertex_index =
9584  get_connected_vertex_number_on_destination_polyline(
9585  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9586 
9587  // If we could not find the vertex index to connect then
9588  // we are in trouble
9589  if (!found_vertex_index)
9590  {
9591  std::stringstream error;
9592  error
9593  << "The current shared boundary (" << bound_id << ") was "
9594  << "marked to have a connection\nto the left with the "
9595  << "boundary (" << uconnection_to_the_left << ").\n"
9596  << "The problem is that the left vertex of the current\n"
9597  << "shared boundary is not in the list of vertices of the\n"
9598  << "boundary to connect.\n\n"
9599  << "This is the left vertex of the current shared boundary\n"
9600  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
9601  << shd_bnd_left_vertex[1] << ")\n\n"
9602  << "This is the list of vertices on the destination "
9603  << "boundary\n";
9604  const unsigned n_v = poly_to_connect_pt->nvertex();
9605  for (unsigned i = 0; i < n_v; i++)
9606  {
9607  Vector<double> cvertex =
9608  poly_to_connect_pt->vertex_coordinate(i);
9609  error
9610  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "<<cvertex[1]<<")\n";
9611  }
9612  throw OomphLibError(
9613  error.str(),
9614  "TriangleMesh::create_shared_polylines_connections()",
9615  OOMPH_EXCEPTION_LOCATION);
9616  } // if (!found_vertex_index)
9617 
9618  // Create the connection, the left vertex of the current
9619  // shared boundary is connected with the vertex_index-th
9620  // vertex on the destination boundary
9621  shd_poly_pt->connect_initial_vertex_to_polyline(
9622  poly_to_connect_pt, vertex_index);
9623 
9624  } // if (!connecting_to_an_overlaped_boundary)
9625  else
9626  {
9627  // If the boundary is marked to be overlaped by a shared
9628  // boundary then get that shared boundary and look for
9629  // the connection in that boundary
9630 
9631  // The vertex where to store the index to connect
9632  unsigned vertex_index = 0;
9633  // A flag to indicate if the connection was found
9634  bool found_vertex_index = false;
9635 
9636  // Get the shared boundary id that is overlaping the
9637  // internal boundary
9638  Vector<unsigned> dst_shd_bnd_ids;
9639  get_shared_boundaries_overlapping_internal_boundary(
9640  uconnection_to_the_left, dst_shd_bnd_ids);
9641 
9642  // Get the number of shared polylines that were found to
9643  // overlap the internal boundary
9644  const unsigned n_shd_bnd_overlap_int_bnd =
9645  dst_shd_bnd_ids.size();
9646 
9647  // Loop over the shared boundaries that overlap the
9648  // internal boundary and look for the vertex to connect
9649  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
9650  {
9651  // Get the shared polyline
9652  const unsigned new_connection_to_the_left =
9653  dst_shd_bnd_ids[ss];
9654 
9655  // Get the shared polyline that is overlaping the
9656  // internal boundary
9657  poly_to_connect_pt =
9658  boundary_polyline_pt(new_connection_to_the_left);
9659 
9660  if (poly_to_connect_pt!=0)
9661  {
9662  // Look for the vertex number in the destination
9663  // shared polyline
9664  found_vertex_index =
9665  get_connected_vertex_number_on_destination_polyline(
9666  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9667  } // if (poly_to_connect_pt!=0)
9668 
9669  // If we have found the vertex to connect then
9670  // break the loop
9671  if (found_vertex_index)
9672  {
9673  break;
9674  } // if (found_vertex_index)
9675 
9676  } // for (ss < n_shd_bnd_overlaping_int_bnd)
9677 
9678 #ifdef PARANOID
9679  // If we could not find the vertex index to connect then
9680  // we are in trouble
9681  if (!found_vertex_index)
9682  {
9683  std::stringstream error;
9684  error
9685  << "The current shared boundary (" << bound_id << ") was "
9686  << "marked to have a connection\nto the left with the "
9687  << "boundary (" << uconnection_to_the_left << ").\n"
9688  << "This last boundary is marked to be overlaped by "
9689  << "shared boundaries\n"
9690  << "The problem is that the left vertex of the current\n"
9691  << "shared boundary is not in the list of vertices of the\n"
9692  << "boundary to connect.\n\n"
9693  << "This is the left vertex of the current shared boundary\n"
9694  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
9695  << shd_bnd_left_vertex[1] << ")\n\n"
9696  << "This is the list of vertices on the destination "
9697  << "boundary\n";
9698  Vector<unsigned> dst_shd_bnd_ids;
9699  get_shared_boundaries_overlapping_internal_boundary(
9700  uconnection_to_the_left, dst_shd_bnd_ids);
9701  const unsigned n_shd_bnd_overlap_int_bnd =
9702  dst_shd_bnd_ids.size();
9703  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
9704  {
9705  const unsigned new_connection_to_the_left =
9706  dst_shd_bnd_ids[ss];
9707  poly_to_connect_pt =
9708  boundary_polyline_pt(new_connection_to_the_left);
9709  if (poly_to_connect_pt != 0)
9710  {
9711  const unsigned shd_bnd_id_overlap =
9712  poly_to_connect_pt->boundary_id();
9713  error << "Shared boundary id("
9714  << shd_bnd_id_overlap << ")\n";
9715  const unsigned n_v = poly_to_connect_pt->nvertex();
9716  for (unsigned i = 0; i < n_v; i++)
9717  {
9718  Vector<double> cvertex =
9719  poly_to_connect_pt->vertex_coordinate(i);
9720  error
9721  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
9722  <<cvertex[1]<<")\n";
9723  }
9724  } // if (poly_to_connect_pt != 0)
9725  } // for (ss < n_shd_bnd_overlap_int_bnd)
9726 
9727  throw OomphLibError(
9728  error.str(),
9729  "TriangleMesh::create_shared_polylines_connections()",
9730  OOMPH_EXCEPTION_LOCATION);
9731 
9732  } // if (!found_vertex_index)
9733 #endif
9734 
9735  // Create the connection, the left vertex of the current
9736  // shared boundary is connected with the vertex_index-th
9737  // vertex on the destination boundary
9738  shd_poly_pt->connect_initial_vertex_to_polyline(
9739  poly_to_connect_pt, vertex_index);
9740 
9741  } // else if (!connecting_to_an_overlaped_boundary)
9742 
9743  } // if (!connecting_to_an_split_boundary)
9744  else
9745  {
9746  // If the boundary was split then we need to look for the
9747  // vertex in the sub-polylines
9748 
9749  // Get the sub-polylines vector
9750  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
9751  boundary_subpolylines(uconnection_to_the_left);
9752 
9753  // Get the number of sub-polylines
9754  const unsigned nsub_poly = tmp_vector_subpolylines.size();
9755 #ifdef PARANOID
9756  if (nsub_poly <= 1)
9757  {
9758  std::ostringstream error_message;
9759  error_message
9760  <<"The boundary (" << uconnection_to_the_left << ") was "
9761  << "marked to be splitted but\n"
9762  << "there are only ("<<nsub_poly<<") polylines to "
9763  << "represent it.\n";
9764  throw OomphLibError(
9765  error_message.str(),
9766  "TriangleMesh::create_shared_polylines_connections()",
9767  OOMPH_EXCEPTION_LOCATION);
9768  } // if (nsub_poly <= 1)
9769 #endif
9770  // We need to check if the boundary is marked to be
9771  // overlaped by an internal boundary, if that is the case
9772  // we need to check for each indivual subpolyline, and for
9773  // those overlaped by a shared polyline look for the
9774  // vertex in the shared polyline representation instead of
9775  // the original subpolyline
9776 
9777  // ... check if the boundary is marked to be overlaped by
9778  // a shared boundary
9779  if (!connecting_to_an_overlaped_boundary)
9780  {
9781  // We can work without checking the subpolylines
9782  // individually
9783 
9784  // The vertex where to store the index to connect
9785  unsigned vertex_index = 0;
9786  // The subpoly number to connect
9787  unsigned sub_poly_to_connect = 0;
9788  // A flag to indicate if the connection was found
9789  bool found_vertex_index = false;
9790 
9791  // Look for the vertex number to connect on each of the
9792  // subpolyines
9793  for (unsigned isub = 0; isub < nsub_poly; isub++)
9794  {
9795  // Assign the pointer to the sub-polyline
9796  poly_to_connect_pt = tmp_vector_subpolylines[isub];
9797  // Search for the vertex in the current sub-polyline
9798  found_vertex_index =
9799  get_connected_vertex_number_on_destination_polyline(
9800  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9801  // If we have found the vertex to connect then break the
9802  // loop
9803  if (found_vertex_index)
9804  {
9805  // But first save the subpoly number (chunk), that
9806  // will be used to perform the connection
9807  sub_poly_to_connect = isub;
9808  break;
9809  } // if (found_vertex_index)
9810  } // for (isub < nsub_poly)
9811 
9812 #ifdef PARANOID
9813  // If we could not find the vertex index to connect then
9814  // we are in trouble
9815  if (!found_vertex_index)
9816  {
9817  std::stringstream error;
9818  error
9819  << "The current shared boundary (" << bound_id << ") was "
9820  << "marked to have a connection\nto the left with the "
9821  << "boundary (" << uconnection_to_the_left << ").\n"
9822  << "The problem is that the left vertex of the current\n"
9823  << "shared boundary is not in the list of vertices of any\n"
9824  << "of the sub polylines that represent the boundary to\n"
9825  << "connect.\n\n"
9826  << "This is the left vertex of the current shared boundary\n"
9827  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
9828  << shd_bnd_left_vertex[1] << ")\n\n"
9829  << "This is the list of vertices on the destination "
9830  << "boundary\n";
9831  for (unsigned p = 0; p < nsub_poly; p++)
9832  {
9833  error << "Subpolyline #("<< p << ")\n";
9834  poly_to_connect_pt = tmp_vector_subpolylines[p];
9835  const unsigned n_v = poly_to_connect_pt->nvertex();
9836  for (unsigned i = 0; i < n_v; i++)
9837  {
9838  Vector<double> cvertex =
9839  poly_to_connect_pt->vertex_coordinate(i);
9840  error
9841  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
9842  <<cvertex[1]<<")\n";
9843  }
9844  } // for (p < nsub_poly)
9845  throw OomphLibError(
9846  error.str(),
9847  "TriangleMesh::create_shared_polylines_connections()",
9848  OOMPH_EXCEPTION_LOCATION);
9849  } // if (!found_vertex_index)
9850 #endif
9851 
9852  // Create the connection, the left vertex of the current
9853  // shared boundary is connected with the vertex_index-th
9854  // vertex of sub_poly_to_connect-th subpolyline of the
9855  // destination boundary
9856  shd_poly_pt->connect_initial_vertex_to_polyline(
9857  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
9858 
9859  } // if (!connecting_to_an_overlaped_boundary)
9860  else
9861  {
9862  // We first look on the shared boundaries that overlap
9863  // the internal boundaries and the look for the
9864  // sub-polylines that are not marked as being overlaped
9865  // by shared boundaries
9866 
9867  // The vertex where to store the index to connect
9868  unsigned vertex_index = 0;
9869  // The subpoly number to connect
9870  unsigned sub_poly_to_connect = 0;
9871  // A flag to indicate if the connection was found
9872  bool found_vertex_index = false;
9873 
9874  // Get the shared boundaries id that are overlaping the
9875  // internal boundary
9876  Vector<unsigned> dst_shd_bnd_ids;
9877  get_shared_boundaries_overlapping_internal_boundary(
9878  uconnection_to_the_left, dst_shd_bnd_ids);
9879 
9880  // Get the number of shared polylines that were found to
9881  // overlap the internal boundary
9882  const unsigned n_shd_bnd_overlap_int_bnd =
9883  dst_shd_bnd_ids.size();
9884 
9885  // Loop over the shared boundaries that overlap the
9886  // internal boundary and look for the vertex to connect
9887  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
9888  {
9889  // Get the shared polyline
9890  const unsigned new_connection_to_the_left =
9891  dst_shd_bnd_ids[ss];
9892 
9893  // Make sure that the destination polyline is not the
9894  // same as the current shared polyline
9895  if (bound_id != new_connection_to_the_left)
9896  {
9897  // Get the shared polyline that is overlaping the
9898  // internal boundary
9899  poly_to_connect_pt =
9900  boundary_polyline_pt(new_connection_to_the_left);
9901 
9902  if (poly_to_connect_pt != 0)
9903  {
9904  // Look for the vertex number in the destination
9905  // shared polyline
9906  found_vertex_index =
9907  get_connected_vertex_number_on_destination_polyline(
9908  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9909  } // if (poly_to_connect_pt != 0)
9910 
9911  // If we have found the vertex to connect then
9912  // break the loop
9913  if (found_vertex_index)
9914  {
9915  break;
9916  } // if (found_vertex_index)
9917 
9918  } // if (bound_id != new_connection_to_the_left)
9919 
9920  } // for (ss < n_shd_bnd_overlaping_int_bnd)
9921 
9922  // If we have not yet found the vertex then look for it
9923  // in the sub-polylines that are not overlaped by shared
9924  // boundaries
9925  if (!found_vertex_index)
9926  {
9927  // Look for the vertex number to connect on each of
9928  // the subpolyines
9929  for (unsigned isub = 0; isub < nsub_poly; isub++)
9930  {
9931  // Only work with those sub-polylines that are not
9932  // overlaped by shared boundaries
9933  if (!boundary_marked_as_shared_boundary(
9934  uconnection_to_the_left, isub))
9935  {
9936  // Assign the pointer to the sub-polyline
9937  poly_to_connect_pt = tmp_vector_subpolylines[isub];
9938  // Search for the vertex in the current sub-polyline
9939  found_vertex_index =
9940  get_connected_vertex_number_on_destination_polyline(
9941  poly_to_connect_pt, shd_bnd_left_vertex, vertex_index);
9942  // If we have found the vertex to connect then break the
9943  // loop
9944  if (found_vertex_index)
9945  {
9946  // But first save the subpoly number (chunk), that
9947  // will be used to perform the connection
9948  sub_poly_to_connect = isub;
9949  break;
9950  } // if (found_vertex_index)
9951 
9952  } // if (not overlaped by shared boundary)
9953 
9954  } // for (isub < nsub_poly)
9955 
9956  } // if (!found_vertex_index)
9957 
9958 #ifdef PARANOID
9959  // If we could not find the vertex index to connect then
9960  // we are in trouble
9961  if (!found_vertex_index)
9962  {
9963  std::stringstream error;
9964  error
9965  << "The current shared boundary (" << bound_id << ") was "
9966  << "marked to have a connection\nto the left with the "
9967  << "boundary (" << uconnection_to_the_left << ").\n"
9968  << "This last boundary is marked to be overlaped by "
9969  << "shared boundaries\n"
9970  << "The problem is that the left vertex of the current\n"
9971  << "shared boundary is not in the list of vertices of "
9972  << "the\nboundary to connect.\n\n"
9973  << "This is the left vertex of the current shared "
9974  << "boundary\n"
9975  << "Left vertex: (" << shd_bnd_left_vertex[0] << ", "
9976  << shd_bnd_left_vertex[1] << ")\n\n"
9977  << "This is the list of vertices on the destination "
9978  << "boundary (only those subpolylines not marked as "
9979  << "overlaped by\nshared boundaries)\n";
9980  for (unsigned p = 0; p < nsub_poly; p++)
9981  {
9982  if (!boundary_marked_as_shared_boundary(
9983  uconnection_to_the_left, p))
9984  {
9985  error << "Subpolyline #("<< p << ")\n";
9986  poly_to_connect_pt = tmp_vector_subpolylines[p];
9987  const unsigned n_v = poly_to_connect_pt->nvertex();
9988  for (unsigned i = 0; i < n_v; i++)
9989  {
9990  Vector<double> cvertex =
9991  poly_to_connect_pt->vertex_coordinate(i);
9992  error
9993  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
9994  <<cvertex[1]<<")\n";
9995  }
9996  } // Not marked as overlaped
9997  } // for (p < nsub_poly)
9998  error << "\nThis is the list of vertices of the shared "
9999  << "polylines that overlap\nthe internal "
10000  << "boundary\n";
10001  Vector<unsigned> dst_shd_bnd_ids;
10002  get_shared_boundaries_overlapping_internal_boundary(
10003  uconnection_to_the_left, dst_shd_bnd_ids);
10004  const unsigned n_shd_bnd_overlap_int_bnd =
10005  dst_shd_bnd_ids.size();
10006  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10007  {
10008  const unsigned new_connection_to_the_left =
10009  dst_shd_bnd_ids[ss];
10010  poly_to_connect_pt =
10011  boundary_polyline_pt(new_connection_to_the_left);
10012  if (poly_to_connect_pt != 0)
10013  {
10014  const unsigned shd_bnd_id_overlap =
10015  poly_to_connect_pt->boundary_id();
10016  error << "Shared boundary id("
10017  << shd_bnd_id_overlap << ")\n";
10018  const unsigned n_v = poly_to_connect_pt->nvertex();
10019  for (unsigned i = 0; i < n_v; i++)
10020  {
10021  Vector<double> cvertex =
10022  poly_to_connect_pt->vertex_coordinate(i);
10023  error
10024  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
10025  <<cvertex[1]<<")\n";
10026  }
10027  } // if (poly_to_connect_pt != 0)
10028  } // for (ss < n_shd_bnd_overlap_int_bnd)
10029 
10030  throw OomphLibError(
10031  error.str(),
10032  "TriangleMesh::create_shared_polylines_connections()",
10033  OOMPH_EXCEPTION_LOCATION);
10034  } // if (!found_vertex_index)
10035 #endif
10036 
10037  // Create the connection, the left vertex of the current
10038  // shared boundary is connected with the vertex_index-th
10039  // vertex of sub_poly_to_connect-th subpolyline of the
10040  // destination boundary
10041  shd_poly_pt->connect_initial_vertex_to_polyline(
10042  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
10043 
10044  } // else if (!connecting_to_an_overlaped_boundary)
10045 
10046  } // else if (!connecting_to_an_split_boundary)
10047 
10048  } // if (connection_to_the_left != -1)
10049 
10050  // --------------------------------------------------------------
10051  // Connection to the right
10052  if (is_connected_to_the_right)
10053  {
10054  // Get the unsigned version of the bound id to connect to
10055  // the right
10056  const unsigned uconnection_to_the_right =
10057  shd_poly_pt->final_vertex_connected_bnd_id();
10058 
10059  // The pointer to the boundary to connect
10060  TriangleMeshPolyLine *poly_to_connect_pt = 0;
10061 
10062  // Flag to indicate we are trying to connect to an split
10063  // boundary
10064  bool connecting_to_an_split_boundary = false;
10065 
10066  // Flag to indicate we are trying to connecto to an internal
10067  // boundary that is overlaped by a shared boundary
10068  bool connecting_to_an_overlaped_boundary = false;
10069 
10070  // Check if the connection is with itself
10071  if (uconnection_to_the_right == bound_id)
10072  {
10073  // Set the pointer to the polyline to connect
10074  poly_to_connect_pt = shd_poly_pt;
10075  }
10076  else
10077  {
10078  // Get the initial shared boundary ids
10079  const unsigned initial_shd_bnd_id = initial_shared_boundary_id();
10080  // Check if the boundary to connect is a shared polyline
10081  if (uconnection_to_the_right >= initial_shd_bnd_id)
10082  {
10083  // Get the polyline pointer representing the destination
10084  // boundary
10085  poly_to_connect_pt =
10086  boundary_polyline_pt(uconnection_to_the_right);
10087  } // if (uconnection_to_the_left >= initial_shd_bnd_id)
10088  else
10089  {
10090  // If we are going to connect to an original boundary
10091  // verify if the boundary was splitted during the
10092  // distribution process to consider all the chunks
10093  // (sub-polylines) of the boundary
10094  if (boundary_was_splitted(uconnection_to_the_right))
10095  {
10096  connecting_to_an_split_boundary = true;
10097  } // if (boundary_was_splitted(uconnection_to_the_right))
10098 
10099  // If we are going to connect to an original boundary
10100  // verify if the boundary, or any of its chunks is
10101  // marked to be overlapped by a shared boundary, if that
10102  // is the case we first check for connections in the
10103  // shared boundary that overlaps the internal boundary,
10104  // or the chunks, and then check for connections in the
10105  // original boundary
10106  if (connecting_to_an_split_boundary)
10107  {
10108  // Get the number of chucks that represent the
10109  // destination boundary
10110  const unsigned n_sub_poly =
10111  nboundary_subpolylines(uconnection_to_the_right);
10112  // Now loop over the chunks of the destination
10113  // boundary and if any of them is marked to be
10114  // overlaped by a shared boundary then set the flag
10115  // and break the loop
10116  for (unsigned ii =0; ii < n_sub_poly; ii++)
10117  {
10118  if (boundary_marked_as_shared_boundary(
10119  uconnection_to_the_right, ii))
10120  {
10121  // Mark the boundary as being overlaped by a
10122  // shared boundary
10123  connecting_to_an_overlaped_boundary = true;
10124  // Break, no need to look for more overlapings
10125  break;
10126  } // if (boundary_marked_as_shared_boundary(...))
10127  } // for (ii < n_sub_poly)
10128  } // if (connecting_to_an_split_boundary)
10129  else
10130  {
10131  // If not connecting to an split boundary then check
10132  // if the whole destination boundary is overlaped by
10133  // an internal boundary
10134  if (boundary_marked_as_shared_boundary(
10135  uconnection_to_the_right, 0))
10136  {
10137  // Mark the boundary as being overlaped by a shared
10138  // boundary
10139  connecting_to_an_overlaped_boundary = true;
10140  } // if (boundary_marked_as_shared_boundary(...))
10141  } // else if (connecting_to_an_split_boundary)
10142 
10143  // If we are connecting neither to an split boundary nor
10144  // an overlaped boundary then get the pointer to the
10145  // original boundary
10146  if (!(connecting_to_an_split_boundary ||
10147  connecting_to_an_overlaped_boundary))
10148  {
10149  // Get the polyline pointer representing the
10150  // destination boundary
10151  poly_to_connect_pt =
10152  boundary_polyline_pt(uconnection_to_the_right);
10153  } // else if (NOT split, NOT overlaped)
10154  } // else if (uconnection_to_the_right >= initial_shd_bnd_id)
10155 
10156  } // else if (uconnection_to_the_right == bound_id)
10157 
10158 #ifdef PARANOID
10159  // If we are not connecting to an original boundary
10160  // (connecting to the same shared boundary or to another
10161  // shared boundary) then the boundary should not be marked
10162  // as split
10163  if (!connecting_to_an_split_boundary)
10164  {
10165  if (boundary_was_splitted(uconnection_to_the_right))
10166  {
10167  std::stringstream error;
10168  error
10169  << "The current shared boundary (" << bound_id << ") was "
10170  << "marked to have a connection\nto the right with the "
10171  << "boundary (" << uconnection_to_the_right << ").\n"
10172  << "The problem is that the destination boundary (possibly\n"
10173  << "another shared boundary) is marked to be split\n"
10174  << "There should not be split shared boundaries\n\n";
10175  throw OomphLibError(
10176  error.str(),
10177  "TriangleMesh::create_shared_polylines_connections()",
10178  OOMPH_EXCEPTION_LOCATION);
10179  }
10180  } // if (!connecting_to_an_split_boundary)
10181 #endif
10182 
10183  // Now look for the vertex number on the destination
10184  // boundary(ies) -- in case that the boundary was split ---
10185 
10186  // Do not check for same orientation, that was previously
10187  // worked by interchanging the connections boundaries (if
10188  // necessary)
10189 
10190  // Get the right vertex in the shared boundary
10191  Vector<double> shd_bnd_right_vertex =
10192  shd_poly_pt->vertex_coordinate(n_vertex-1);
10193 
10194  // If the boundary was not split then inmediately look for
10195  // the vertex index in the destination boundary
10196  if (!connecting_to_an_split_boundary)
10197  {
10198  // ... check if the boundary is marked to be overlaped by
10199  // a shared boundary
10200  if (!connecting_to_an_overlaped_boundary)
10201  {
10202  // If that is not the case then we can safely look for
10203  // the vertex number on the destination boundar
10204 
10205  unsigned vertex_index = 0;
10206  const bool found_vertex_index =
10207  get_connected_vertex_number_on_destination_polyline(
10208  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10209 
10210  // If we could not find the vertex index to connect then
10211  // we are in trouble
10212  if (!found_vertex_index)
10213  {
10214  std::stringstream error;
10215  error
10216  << "The current shared boundary (" << bound_id << ") was "
10217  << "marked to have a connection\nto the right with the "
10218  << "boundary (" << uconnection_to_the_right << ").\n"
10219  << "The problem is that the right vertex of the current\n"
10220  << "shared boundary is not in the list of vertices of the\n"
10221  << "boundary to connect.\n\n"
10222  << "This is the right vertex of the current shared boundary\n"
10223  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10224  << shd_bnd_right_vertex[1] << ")\n\n"
10225  << "This is the list of vertices on the destination boundary\n";
10226  const unsigned n_v = poly_to_connect_pt->nvertex();
10227  for (unsigned i = 0; i < n_v; i++)
10228  {
10229  Vector<double> cvertex =
10230  poly_to_connect_pt->vertex_coordinate(i);
10231  error
10232  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "<<cvertex[1]<<")\n";
10233  }
10234  throw OomphLibError(
10235  error.str(),
10236  "TriangleMesh::create_shared_polylines_connections()",
10237  OOMPH_EXCEPTION_LOCATION);
10238  } // if (!found_vertex_index)
10239 
10240  // Create the connection, the right vertex of the current
10241  // shared boundary is connected with the vertex_index-th
10242  // vertex on the destination boundary
10243  shd_poly_pt->connect_final_vertex_to_polyline(
10244  poly_to_connect_pt, vertex_index);
10245 
10246  } // if (!connecting_to_an_overlaped_boundary)
10247  else
10248  {
10249  // If the boundary is marked to be overlaped by a shared
10250  // boundary then get that shared boundary and look for
10251  // the connection in that boundary
10252 
10253  // The vertex where to store the index to connect
10254  unsigned vertex_index = 0;
10255  // A flag to indicate if the connection was found
10256  bool found_vertex_index = false;
10257 
10258  // Get the shared boundary id that is overlaping the
10259  // internal boundary
10260  Vector<unsigned> dst_shd_bnd_ids;
10261  get_shared_boundaries_overlapping_internal_boundary(
10262  uconnection_to_the_right, dst_shd_bnd_ids);
10263 
10264  // Get the number of shared polylines that were found to
10265  // overlap the internal boundary
10266  const unsigned n_shd_bnd_overlap_int_bnd =
10267  dst_shd_bnd_ids.size();
10268 
10269  // Loop over the shared boundaries that overlap the
10270  // internal boundary and look for the vertex to connect
10271  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10272  {
10273  // Get the shared polyline
10274  const unsigned new_connection_to_the_right =
10275  dst_shd_bnd_ids[ss];
10276 
10277  // Get the shared polyline that is overlaping the
10278  // internal boundary
10279  poly_to_connect_pt =
10280  boundary_polyline_pt(new_connection_to_the_right);
10281 
10282  if (poly_to_connect_pt!=0)
10283  {
10284  // Look for the vertex number in the destination
10285  // shared polyline
10286  found_vertex_index =
10287  get_connected_vertex_number_on_destination_polyline(
10288  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10289  } // if (poly_to_connect_pt!=0)
10290 
10291  // If we have found the vertex to connect then
10292  // break the loop
10293  if (found_vertex_index)
10294  {
10295  break;
10296  } // if (found_vertex_index)
10297 
10298  } // for (ss < n_shd_bnd_overlaping_int_bnd)
10299 
10300 #ifdef PARANOID
10301  // If we could not find the vertex index to connect then
10302  // we are in trouble
10303  if (!found_vertex_index)
10304  {
10305  std::stringstream error;
10306  error
10307  << "The current shared boundary (" << bound_id << ") was "
10308  << "marked to have a connection\nto the right with the "
10309  << "boundary (" << uconnection_to_the_right << ").\n"
10310  << "This last boundary is marked to be overlaped by "
10311  << "shared boundaries\n"
10312  << "The problem is that the right vertex of the current\n"
10313  << "shared boundary is not in the list of vertices of the\n"
10314  << "boundary to connect.\n\n"
10315  << "This is the right vertex of the current shared boundary\n"
10316  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10317  << shd_bnd_right_vertex[1] << ")\n\n"
10318  << "This is the list of vertices on the destination "
10319  << "boundary\n";
10320  Vector<unsigned> dst_shd_bnd_ids;
10321  get_shared_boundaries_overlapping_internal_boundary(
10322  uconnection_to_the_right, dst_shd_bnd_ids);
10323  const unsigned n_shd_bnd_overlap_int_bnd =
10324  dst_shd_bnd_ids.size();
10325  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10326  {
10327  const unsigned new_connection_to_the_right =
10328  dst_shd_bnd_ids[ss];
10329  poly_to_connect_pt =
10330  boundary_polyline_pt(new_connection_to_the_right);
10331  if (poly_to_connect_pt != 0)
10332  {
10333  const unsigned shd_bnd_id_overlap =
10334  poly_to_connect_pt->boundary_id();
10335  error << "Shared boundary id("
10336  << shd_bnd_id_overlap << ")\n";
10337  const unsigned n_v = poly_to_connect_pt->nvertex();
10338  for (unsigned i = 0; i < n_v; i++)
10339  {
10340  Vector<double> cvertex =
10341  poly_to_connect_pt->vertex_coordinate(i);
10342  error
10343  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
10344  <<cvertex[1]<<")\n";
10345  }
10346  } // if (poly_to_connect_pt != 0)
10347  } // for (ss < n_shd_bnd_overlap_int_bnd)
10348 
10349  throw OomphLibError(
10350  error.str(),
10351  "TriangleMesh::create_shared_polylines_connections()",
10352  OOMPH_EXCEPTION_LOCATION);
10353 
10354  } // if (!found_vertex_index)
10355 #endif
10356 
10357  // Create the connection, the right vertex of the
10358  // current shared boundary is connected with the
10359  // vertex_index-th vertex on the destination boundary
10360  shd_poly_pt->connect_final_vertex_to_polyline(
10361  poly_to_connect_pt, vertex_index);
10362 
10363  } // else if (!connecting_to_an_overlaped_boundary)
10364 
10365  } // if (!connecting_to_an_split_boundary)
10366  else
10367  {
10368  // If the boundary was split then we need to look for the
10369  // vertex in the sub-polylines
10370 
10371  // Get the sub-polylines vector
10372  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
10373  boundary_subpolylines(uconnection_to_the_right);
10374 
10375  // Get the number of sub-polylines
10376  const unsigned nsub_poly = tmp_vector_subpolylines.size();
10377 #ifdef PARANOID
10378  if (nsub_poly <= 1)
10379  {
10380  std::ostringstream error_message;
10381  error_message
10382  <<"The boundary (" << uconnection_to_the_right << ") was "
10383  << "marked to be splitted but\n"
10384  << "there are only ("<<nsub_poly<<") polylines to "
10385  << "represent it.\n";
10386  throw OomphLibError(
10387  error_message.str(),
10388  "TriangleMesh::create_shared_polylines_connections()",
10389  OOMPH_EXCEPTION_LOCATION);
10390  } // if (nsub_poly <= 1)
10391 #endif
10392 
10393  // We need to check if the boundary is marked to be
10394  // overlaped by an internal boundary, if that is the case
10395  // we need to check for each indivual subpolyline, and for
10396  // those overlaped by a shared polyline look for the
10397  // vertex in the shared polyline representation instead of
10398  // the original subpolyline
10399 
10400  // ... check if the boundary is marked to be overlaped by
10401  // a shared boundary
10402  if (!connecting_to_an_overlaped_boundary)
10403  {
10404  // We can work without checking the subpolylines
10405  // individually
10406 
10407  // The vertex where to store the index to connect
10408  unsigned vertex_index = 0;
10409  // The subpoly number to connect
10410  unsigned sub_poly_to_connect = 0;
10411  // A flag to indicate if the connection was found
10412  bool found_vertex_index = false;
10413 
10414  // Look for the vertex number to connect on each of the
10415  // subpolyines
10416  for (unsigned isub = 0; isub < nsub_poly; isub++)
10417  {
10418  // Assign the pointer to the sub-polyline
10419  poly_to_connect_pt = tmp_vector_subpolylines[isub];
10420  // Search for the vertex in the current sub-polyline
10421  found_vertex_index =
10422  get_connected_vertex_number_on_destination_polyline(
10423  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10424  // If we have found the vertex to connect then break the
10425  // loop
10426  if (found_vertex_index)
10427  {
10428  // But first save the subpoly number (chunk), that
10429  // will be used to perform the connection
10430  sub_poly_to_connect = isub;
10431  break;
10432  } // if (found_vertex_index)
10433  } // for (isub < nsub_poly)
10434 
10435 #ifdef PARANOID
10436  // If we could not find the vertex index to connect then
10437  // we are in trouble
10438  if (!found_vertex_index)
10439  {
10440  std::stringstream error;
10441  error
10442  << "The current shared boundary (" << bound_id << ") was "
10443  << "marked to have a connection\nto the right with the "
10444  << "boundary (" << uconnection_to_the_right << ").\n"
10445  << "The problem is that the right vertex of the current\n"
10446  << "shared boundary is not in the list of vertices of any\n"
10447  << "of the sub polylines that represent the boundary to\n"
10448  << "connect.\n\n"
10449  << "This is the right vertex of the current shared boundary\n"
10450  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10451  << shd_bnd_right_vertex[1] << ")\n\n"
10452  << "This is the list of vertices on the destination "
10453  << "boundary\n";
10454  for (unsigned p = 0; p < nsub_poly; p++)
10455  {
10456  error << "Subpolyline #("<< p << ")\n";
10457  poly_to_connect_pt = tmp_vector_subpolylines[p];
10458  const unsigned n_v = poly_to_connect_pt->nvertex();
10459  for (unsigned i = 0; i < n_v; i++)
10460  {
10461  Vector<double> cvertex =
10462  poly_to_connect_pt->vertex_coordinate(i);
10463  error
10464  <<"Vertex #"<<i<<": ("<<cvertex[0]
10465  <<", "<<cvertex[1]<<")\n";
10466  }
10467  } // for (p < nsub_poly)
10468  throw OomphLibError(
10469  error.str(),
10470  "TriangleMesh::create_shared_polylines_connections()",
10471  OOMPH_EXCEPTION_LOCATION);
10472  } // if (!found_vertex_index)
10473 #endif
10474 
10475  // Create the connection, the right vertex of the current
10476  // shared boundary is connected with the vertex_index-th
10477  // vertex of sub_poly_to_connect-th subpolyline of the
10478  // destination boundary
10479  shd_poly_pt->connect_final_vertex_to_polyline(
10480  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
10481 
10482  } // if (!connecting_to_an_overlaped_boundary)
10483  else
10484  {
10485  // We first look on the shared boundaries that overlap
10486  // the internal boundaries and the look for the
10487  // sub-polylines that are not marked as being overlaped
10488  // by shared boundaries
10489 
10490  // The vertex where to store the index to connect
10491  unsigned vertex_index = 0;
10492  // The subpoly number to connect
10493  unsigned sub_poly_to_connect = 0;
10494  // A flag to indicate if the connection was found
10495  bool found_vertex_index = false;
10496 
10497  // Get the shared boundaries id that are overlaping the
10498  // internal boundary
10499  Vector<unsigned> dst_shd_bnd_ids;
10500  get_shared_boundaries_overlapping_internal_boundary(
10501  uconnection_to_the_right, dst_shd_bnd_ids);
10502 
10503  // Get the number of shared polylines that were found to
10504  // overlap the internal boundary
10505  const unsigned n_shd_bnd_overlap_int_bnd =
10506  dst_shd_bnd_ids.size();
10507 
10508  // Loop over the shared boundaries that overlap the
10509  // internal boundary and look for the vertex to connect
10510  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10511  {
10512  // Get the shared polyline
10513  const unsigned new_connection_to_the_right =
10514  dst_shd_bnd_ids[ss];
10515 
10516  // Make sure that the destination polyline is not the
10517  // same as the current shared polyline
10518  if (bound_id != new_connection_to_the_right)
10519  {
10520  // Get the shared polyline that is overlaping the
10521  // internal boundary
10522  poly_to_connect_pt =
10523  boundary_polyline_pt(new_connection_to_the_right);
10524 
10525  if (poly_to_connect_pt != 0)
10526  {
10527  // Look for the vertex number in the destination
10528  // shared polyline
10529  found_vertex_index =
10530  get_connected_vertex_number_on_destination_polyline(
10531  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10532  } // if (poly_to_connect_pt != 0)
10533 
10534  // If we have found the vertex to connect then
10535  // break the loop
10536  if (found_vertex_index)
10537  {
10538  break;
10539  } // if (found_vertex_index)
10540 
10541  } // if (bound_id != new_connection_to_the_right)
10542 
10543  } // for (ss < n_shd_bnd_overlaping_int_bnd)
10544 
10545  // If we have not yet found the vertex then look for it
10546  // in the sub-polylines that are not overlaped by shared
10547  // boundaries
10548  if (!found_vertex_index)
10549  {
10550  // Look for the vertex number to connect on each of
10551  // the subpolyines
10552  for (unsigned isub = 0; isub < nsub_poly; isub++)
10553  {
10554  // Only work with those sub-polylines that are not
10555  // overlaped by shared boundaries
10556  if (!boundary_marked_as_shared_boundary(
10557  uconnection_to_the_right, isub))
10558  {
10559  // Assign the pointer to the sub-polyline
10560  poly_to_connect_pt = tmp_vector_subpolylines[isub];
10561  // Search for the vertex in the current sub-polyline
10562  found_vertex_index =
10563  get_connected_vertex_number_on_destination_polyline(
10564  poly_to_connect_pt, shd_bnd_right_vertex, vertex_index);
10565  // If we have found the vertex to connect then break the
10566  // loop
10567  if (found_vertex_index)
10568  {
10569  // But first save the subpoly number (chunk), that
10570  // will be used to perform the connection
10571  sub_poly_to_connect = isub;
10572  break;
10573  } // if (found_vertex_index)
10574 
10575  } // if (not overlaped by shared boundary)
10576 
10577  } // for (isub < nsub_poly)
10578 
10579  } // if (!found_vertex_index)
10580 
10581 #ifdef PARANOID
10582  // If we could not find the vertex index to connect then
10583  // we are in trouble
10584  if (!found_vertex_index)
10585  {
10586  std::stringstream error;
10587  error
10588  << "The current shared boundary (" << bound_id << ") was "
10589  << "marked to have a connection\nto the right with the "
10590  << "boundary (" << uconnection_to_the_right << ").\n"
10591  << "This last boundary is marked to be overlaped by "
10592  << "shared boundaries\n"
10593  << "The problem is that the right vertex of the current\n"
10594  << "shared boundary is not in the list of vertices of "
10595  << "the\nboundary to connect.\n\n"
10596  << "This is the right vertex of the current shared "
10597  << "boundary\n"
10598  << "Right vertex: (" << shd_bnd_right_vertex[0] << ", "
10599  << shd_bnd_right_vertex[1] << ")\n\n"
10600  << "This is the list of vertices on the destination "
10601  << "boundary (only those subpolylines not marked as "
10602  << "overlaped by\nshared boundaries)\n";
10603  for (unsigned p = 0; p < nsub_poly; p++)
10604  {
10605  if (!boundary_marked_as_shared_boundary(
10606  uconnection_to_the_right, p))
10607  {
10608  error << "Subpolyline #("<< p << ")\n";
10609  poly_to_connect_pt = tmp_vector_subpolylines[p];
10610  const unsigned n_v = poly_to_connect_pt->nvertex();
10611  for (unsigned i = 0; i < n_v; i++)
10612  {
10613  Vector<double> cvertex =
10614  poly_to_connect_pt->vertex_coordinate(i);
10615  error
10616  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
10617  <<cvertex[1]<<")\n";
10618  }
10619  } // Not marked as overlaped
10620  } // for (p < nsub_poly)
10621  error << "\nThis is the list of vertices of the shared "
10622  << "polylines that overlap\nthe internal "
10623  << "boundary\n";
10624  Vector<unsigned> dst_shd_bnd_ids;
10625  get_shared_boundaries_overlapping_internal_boundary(
10626  uconnection_to_the_right, dst_shd_bnd_ids);
10627  const unsigned n_shd_bnd_overlap_int_bnd =
10628  dst_shd_bnd_ids.size();
10629  for (unsigned ss = 0; ss < n_shd_bnd_overlap_int_bnd; ss++)
10630  {
10631  const unsigned new_connection_to_the_right =
10632  dst_shd_bnd_ids[ss];
10633  poly_to_connect_pt =
10634  boundary_polyline_pt(new_connection_to_the_right);
10635  if (poly_to_connect_pt != 0)
10636  {
10637  const unsigned shd_bnd_id_overlap =
10638  poly_to_connect_pt->boundary_id();
10639  error << "Shared boundary id("
10640  << shd_bnd_id_overlap << ")\n";
10641  const unsigned n_v = poly_to_connect_pt->nvertex();
10642  for (unsigned i = 0; i < n_v; i++)
10643  {
10644  Vector<double> cvertex =
10645  poly_to_connect_pt->vertex_coordinate(i);
10646  error
10647  <<"Vertex #"<<i<<": ("<<cvertex[0]<<", "
10648  <<cvertex[1]<<")\n";
10649  }
10650  } // if (poly_to_connect_pt != 0)
10651  } // for (ss < n_shd_bnd_overlap_int_bnd)
10652 
10653  throw OomphLibError(
10654  error.str(),
10655  "TriangleMesh::create_shared_polylines_connections()",
10656  OOMPH_EXCEPTION_LOCATION);
10657  } // if (!found_vertex_index)
10658 #endif
10659 
10660  // Create the connection, the left vertex of the current
10661  // shared boundary is connected with the vertex_index-th
10662  // vertex of sub_poly_to_connect-th subpolyline of the
10663  // destination boundary
10664  shd_poly_pt->connect_final_vertex_to_polyline(
10665  poly_to_connect_pt, vertex_index, sub_poly_to_connect);
10666 
10667  } // else if (!connecting_to_an_overlaped_boundary)
10668 
10669  } // else if (!connecting_to_an_split_boundary)
10670 
10671  } // if (connection_to_the_right != -1)
10672 
10673  } // if (connection_to_the_left != -1 || connection_to_the_right != -1)
10674 
10675  } // for (ipoly < npoly)
10676 
10677  } // for (icurve < ncurves)
10678 
10679  }
10680 
10681  //=======================================================================
10682  // \short Compute the holes left by the halo elements, those adjacent
10683  // to the shared boundaries
10684  //=======================================================================
10685  template<class ELEMENT>
10687  Vector<Vector<double> > &output_holes_coordinates)
10688  {
10689  // Storage for number of processors and current processor
10690  const unsigned n_proc = this->communicator_pt()->nproc();
10691  const unsigned my_rank = this->communicator_pt()->my_rank();
10692 
10693  // Mark those done elements, so we do not repeat any coordinate left
10694  // by repeated halo elements
10695  std::map<FiniteElement*, bool> done_ele;
10696 
10697  // Loop over the processors and get the shared boundaries ids that
10698  // the current processor has with the other processors
10699  for (unsigned iproc = 0; iproc < n_proc; iproc++)
10700  {
10701  // There are shared boundaries only with the other processors
10702  if (iproc != my_rank)
10703  {
10704  // Get the number of shared boundaries with the iproc
10705  const unsigned n_shd_bnd_iproc = nshared_boundaries(my_rank, iproc);
10706 
10707 #ifdef PARANOID
10708  // Get the number of shared boundaries with the iproc, but
10709  // reversing the indexes
10710  const unsigned n_shd_bnd_iproc_rev = nshared_boundaries(iproc, my_rank);
10711  if (n_shd_bnd_iproc != n_shd_bnd_iproc_rev)
10712  {
10713  std::ostringstream error_stream;
10714  error_stream
10715  << "The number of shared boundaries of processor ("
10716  << my_rank << ") with processor(" << iproc << "): ("
10717  << n_shd_bnd_iproc << ")\n"
10718  << "is different from the number of shared boundaries of "
10719  << "processor (" << iproc << ")\nwith processor ("
10720  << my_rank << "): (" << n_shd_bnd_iproc << ")\n\n";
10721  throw OomphLibError(error_stream.str(),
10722  OOMPH_CURRENT_FUNCTION,
10723  OOMPH_EXCEPTION_LOCATION);
10724 
10725  } // if (n_shd_bnd_iproc != n_shd_bnd_iproc_rev)
10726 #endif
10727 
10728  // Loop over the shared boundaries ids
10729  for (unsigned i = 0; i < n_shd_bnd_iproc; i++)
10730  {
10731  // Get the shared boundary id
10732  const unsigned shd_bnd_id = shared_boundaries_ids(my_rank, iproc, i);
10733 
10734  // Get the number of shared boundary elements
10735  const unsigned n_shd_bnd_ele = nshared_boundary_element(shd_bnd_id);
10736 
10737  // Loop over the shared boundary elements
10738  for (unsigned e = 0; e < n_shd_bnd_ele; e++)
10739  {
10740  // Get the shared boundary element
10741  FiniteElement* ele_pt = shared_boundary_element_pt(shd_bnd_id, e);
10742 
10743  // Only work with halo elements
10744  if (ele_pt->is_halo())
10745  {
10746  // If the element has not been visited
10747  if (!done_ele[ele_pt])
10748  {
10749  // Get the number of nodes
10750  const unsigned n_nodes = ele_pt->nnode();
10751 
10752  // Compute the centroid of the element
10753  Vector<double> element_centroid(2, 0.0);
10754  // Loop over the nodes
10755  for (unsigned k = 0; k < n_nodes; k++)
10756  {
10757  Node* tmp_node_pt = ele_pt->node_pt(k);
10758  // Loop over the dimension
10759  for (unsigned d = 0; d < 2; d++)
10760  {
10761  element_centroid[d]+=tmp_node_pt->x(d);
10762  } // for (d < 2)
10763  } // for (k < n_nodes)
10764 
10765  // Average the data
10766  for (unsigned d = 0; d < 2; d++)
10767  {
10768  element_centroid[d] =
10769  element_centroid[d] / (double)n_nodes;
10770  } // for (d < 2)
10771 
10772  // Add the centroid to the output holes
10773  output_holes_coordinates.push_back(element_centroid);
10774 
10775  } // if (!done_ele[ele_pt])
10776 
10777  } // if (ele_pt->is_halo())
10778 
10779  } // for1 (e < n_shd_bnd_ele)
10780 
10781  } // for (i < n_shd_bnd_iproc)
10782 
10783  } // if (iproc != my_rank)
10784 
10785  } // for (iproc < n_proc)
10786 
10787  }
10788 
10789  //======================================================================
10790  // \short Keeps those vertices that define a hole, those that are
10791  // inside closed internal boundaries in the new polygons that define
10792  // the domain. Delete those outside/inside the outer polygons (this
10793  // is required since Triangle can not deal with vertices that define
10794  // holes outside the new outer polygons of the domain)
10795  //======================================================================
10796  template<class ELEMENT>
10798  Vector<TriangleMeshPolygon *> &polygons_pt,
10799  Vector<Vector<double> > &output_holes_coordinates)
10800  {
10801  // General strategy
10802 
10803  // 1) Identify the inner closed boundaries
10804 
10805  // 2) Separate the vertices in three groups
10806 
10807  // --- 2.1) The vertices inside the inner closed boundaries, these
10808  // are not deleted because they define holes
10809 
10810  // --- 2.2) The vertices outside the outer boundaries, these are
10811  // deleted only if they are outside the convex hull defined
10812  // by all the polygons
10813 
10814  // --- 2.3) Any other vertex is deleted
10815 
10816  // Get the number of input holes
10817  const unsigned n_input_holes = output_holes_coordinates.size();
10818 
10819  // Only do something if there are holes
10820  if (n_input_holes == 0)
10821  {
10822  return;
10823  }
10824 
10825  // Get the number of input polygons
10826  const unsigned n_polygons = polygons_pt.size();
10827 
10828  // Store the vertices of all the input polygons
10829  // vertices_polygons[x][ ][ ]: Polygon number
10830  // vertices_polygons[ ][x][ ]: Vertex number
10831  // vertices_polygons[ ][ ][x]: Vertex coordinate
10832  Vector<Vector<Vector<double> > > vertices_polygons(n_polygons);
10833 
10834  // Loop over all the polygons and get the vertices
10835  for (unsigned p = 0; p < n_polygons; p++)
10836  {
10837  // Get the number of polylines associated to the polygon
10838  const unsigned n_polylines = polygons_pt[p]->npolyline();
10839  // Loop over the polylines and get the vertices
10840  for (unsigned pp = 0; pp < n_polylines; pp++)
10841  {
10842  // Get the polyline
10843  const TriangleMeshPolyLine* tmp_poly_pt =
10844  polygons_pt[p]->polyline_pt(pp);
10845  // Get the number of vertices in the polyline
10846  const unsigned n_vertices = tmp_poly_pt->nvertex();
10847  // Loop over the vertices but only add (n_vertices-1) vertices,
10848  // the last vertex of polyline (pp) is the first vertex of
10849  // polyline (pp+1)
10850  for (unsigned v = 0; v < n_vertices-1; v++)
10851  {
10852  // Get the current vertex
10853  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
10854  vertices_polygons[p].push_back(current_vertex);
10855  } // for (v < nvertex)
10856  } // for (p < nouter_polylines)
10857  } // for (p < n_polygons)
10858 
10859  // -------------------------------------------------------------------
10860  // 1) Identify the inner closed boundaries
10861  // -------------------------------------------------------------------
10862 
10863  // A container that indicates if a given polygon should be
10864  // considered as an outer or as an inner polygon. By default all the
10865  // polygons are considered as outer polygons
10866  std::vector<bool> is_outer_polygon(n_polygons, true);
10867 
10868  // We only check for innner polygons if there are more than one
10869  // polygon
10870  if (n_polygons > 1)
10871  {
10872  // Propose an inner polygon, if one of the middle points of its
10873  // edges lies inside any other polygon then the proposed inner
10874  // polygon is marked as an internal polygon
10875 
10876  // Pre-compute the middle points of the edges in the polygons
10877  Vector<Vector<Vector<double> > > polygon_edge_middle_vertex(n_polygons);
10878 
10879  for (unsigned p = 0; p < n_polygons; p++)
10880  {
10881  // Temporary store the vertices of the proposed inner polygon
10882  Vector<Vector<double> > tmp_inner_polygon = vertices_polygons[p];
10883 
10884  // Get the number of vertices in the current proposed inner polygon
10885  const unsigned n_vertices = tmp_inner_polygon.size();
10886 
10887  // Resize with the number of edges in the polygon
10888  polygon_edge_middle_vertex[p].resize(n_vertices-1);
10889 
10890  // Loop over the vertices and compute the middle point in the edge
10891  // that joins each pair of contiguous vertices
10892  for (unsigned e = 0; e < n_vertices - 1; e++)
10893  {
10894  // The dimension
10895  const unsigned dim = 2;
10896  polygon_edge_middle_vertex[p][e].resize(dim);
10897  for (unsigned d = 0; d < dim; d++)
10898  {
10899  polygon_edge_middle_vertex[p][e][d] =
10900  (tmp_inner_polygon[e][d] + tmp_inner_polygon[e+1][d]) / 2.0;
10901  } // for (d < 2)
10902 
10903  } // for (e < n_vertices - 1)
10904 
10905  } // for (p < n_polygons)
10906 
10907  // Loop over the polygons and for every loop propose a different
10908  // inner polygon
10909  for (unsigned idx_inner = 0; idx_inner < n_polygons; idx_inner++)
10910  {
10911  // Flag to indicate that ONE of the middle edge vertices of the
10912  // proposed inner polygon is inside another polygon, this will
10913  // set the proposed inner polygon as an actual inner polygon
10914  bool is_inner_polygon = false;
10915 
10916  // Loop over all the polygons, except the proposed one and check
10917  // if all the middle edges of its edges are inside any other
10918  // polygon
10919  for (unsigned i = 0; i < n_polygons; i++)
10920  {
10921  // Do not check with the polygon itself
10922  if (i != idx_inner)
10923  {
10924  // Get the number of edges of the proposed inner polygon
10925  const unsigned n_edges =
10926  polygon_edge_middle_vertex[idx_inner].size();
10927  // Loop over the middle points in the edges of the current
10928  // proposed inner polygon
10929  for (unsigned e = 0; e < n_edges; e++)
10930  {
10931  // Get the vertex in the current proposed inner polygon
10932  Vector<double> current_vertex =
10933  polygon_edge_middle_vertex[idx_inner][e];
10934  // Check if the current vertex is inside the current i-th
10935  // polygon
10936  const bool is_point_inside =
10937  is_point_inside_polygon_helper(vertices_polygons[i],
10938  current_vertex);
10939 
10940  // If one point is inside then the polygon is inside the
10941  // i-th polygon
10942  if (is_point_inside)
10943  {
10944  // The polygon is an inner polygon
10945  is_inner_polygon = true;
10946  // Break the loop
10947  break;
10948  } // if (is_point_inside)
10949 
10950  } // for (e < n_edges)
10951 
10952  } // if (i != idx_inner)
10953 
10954  // Are all the vertices of the current proposed inner polygon
10955  // inside the i-th polygon
10956  if (is_inner_polygon)
10957  {
10958  // The current proposed inner polygon is an actual inner
10959  // polygon, and is inside the i-th polygon
10960  break;
10961  }
10962 
10963  } // for (i < n_polygons)
10964 
10965  // Is the current proposed inner polygon an actual inner polygon
10966  if (is_inner_polygon)
10967  {
10968  // The current proposed inner polygon is a real inner polygon
10969  is_outer_polygon[idx_inner] = false;
10970  }
10971  else
10972  {
10973  // The current proposed inner polygon IS NOT a real inner
10974  // polygon
10975  is_outer_polygon[idx_inner] = true;
10976  }
10977 
10978  } // for (idx_outer < npolygons)
10979 
10980  } // if (n_polygons > 1)
10981 
10982  // Count the number of outer closed boundaries and inner closed
10983  // boundaries
10984  unsigned n_outer_polygons = 0;
10985  unsigned n_inner_polygons = 0;
10986  // Also get the indexes of the inner polygons
10987  Vector<unsigned> index_inner_polygon;
10988  // Loop over the polygons
10989  for (unsigned i = 0; i < n_polygons; i++)
10990  {
10991  if (is_outer_polygon[i])
10992  {
10993  // Increase the counter for outer polygons
10994  n_outer_polygons++;
10995  }
10996  else
10997  {
10998  // Increase the counter for inner polygons
10999  n_inner_polygons++;
11000  // Store the index of the inner polygon
11001  index_inner_polygon.push_back(i);
11002  }
11003  } // for (i < n_polygons)
11004 
11005  // -------------------------------------------------------------------
11006  // 2) Separate the vertices in three groups
11007 
11008  // --- 2.1) The vertices inside the inner closed boundaries, these are
11009  // not deleted because they define holes
11010 
11011  // --- 2.2) The vertices outside the outer boundaries, these are
11012  // deleted only if they are outside the convex hull defined
11013  // by all the polygons
11014 
11015  // --- 2.3) Any other vertex is deleted
11016  // -------------------------------------------------------------------
11017 
11018  // Keep track of the vertices inside the inner closed boundaries (by
11019  // default all vertices not inside the inner polygons)
11020  std::vector<bool> is_inside_an_inner_polygon(n_input_holes, false);
11021 
11022  // Keep track of the vertices outside the outer closed boundaries
11023  // (by default all the vertices are outside the outer polygons)
11024  std::vector<bool> is_outside_the_outer_polygons(n_input_holes, true);
11025 
11026  // Keep track of the vertices inside the convex hull (by default
11027  // all the vertices are not inside the convex hull)
11028  std::vector<bool> is_inside_the_convex_hull(n_input_holes, false);
11029 
11030  // Mark the vertices inside the inner closed boundaries
11031  Vector<Vector<Vector<double> > >
11032  vertex_inside_inner_polygon(n_inner_polygons);
11033 
11034  // -------------------------------------------------------------------
11035  // Loop over the inner polygons and find all the vertices inside
11036  // each one
11037  for (unsigned i = 0; i < n_inner_polygons; i++)
11038  {
11039  // Get the vertex of the inner polygon
11040  const unsigned ii = index_inner_polygon[i];
11041  // Loop over the vertices defining holes, mark and store those
11042  // inside the inner polygon
11043  for (unsigned h = 0; h < n_input_holes; h++)
11044  {
11045  // Check if the vertex has not been already marked as inside
11046  // another polygon
11047  if (!is_inside_an_inner_polygon[h])
11048  {
11049  // Check if the hole is inside the current inner polygon
11050  const bool is_inside_polygon =
11051  is_point_inside_polygon_helper(vertices_polygons[ii],
11052  output_holes_coordinates[h]);
11053 
11054  // If the vertex is inside the current inner polygon then mark
11055  // it and associate the vertices to the current inner polygon
11056  if (is_inside_polygon)
11057  {
11058  // Set as inside an inner polygon
11059  is_inside_an_inner_polygon[h] = true;
11060  // Associate the vertex to the current inner polygon
11061  vertex_inside_inner_polygon[i].
11062  push_back(output_holes_coordinates[h]);
11063  } // if (is_inside_polygon)
11064 
11065  } // if (!is_inside_an_inner_polygon[h])
11066 
11067  } // for (h < n_input_holes)
11068 
11069  } // for (i < n_polygons)
11070 
11071  // -------------------------------------------------------------------
11072  // Loop over the vertices defining holes and mark those as outside the
11073  // outer polygons
11074  for (unsigned h = 0; h < n_input_holes; h++)
11075  {
11076  // Check if the vertex has not been already marked as inside
11077  // another polygon
11078  if (!is_inside_an_inner_polygon[h])
11079  {
11080  // Loop over the polygons and check if the vertex is outside ALL
11081  // the outer polygons
11082  for (unsigned i = 0; i < n_polygons; i++)
11083  {
11084  // Only work with outer polygons
11085  if (is_outer_polygon[i])
11086  {
11087  // Check if the hole is inside the current outer polygon
11088  const bool is_inside_polygon =
11089  is_point_inside_polygon_helper(vertices_polygons[i],
11090  output_holes_coordinates[h]);
11091 
11092  // If the vertex is inside the current outer polygon then
11093  // mark it and break the loop (it is not outside ALL the
11094  // polygons)
11095  if (is_inside_polygon)
11096  {
11097  // Set as inside an outer polygon
11098  is_outside_the_outer_polygons[h] = false;
11099  // Break the loop
11100  break;
11101  } // if (is_inside_polygon)
11102 
11103  } // if (is_outer_polygon[i])
11104 
11105  } // for (i < n_polygons)
11106 
11107  } // if (!is_inside_an_inner_polygon[h])
11108  else
11109  {
11110  // If the vertex is inside an inner polygon then it is inside an
11111  // outer polygon
11112  is_outside_the_outer_polygons[h] = false;
11113  } // else if (!is_inside_an_inner_polygon[h])
11114 
11115  } // for (h < n_input_holes)
11116 
11117  // -------------------------------------------------------------------
11118  // Compute the convex hull Create the data structure
11119  std::vector<Point> input_vertices_convex_hull;
11120  // Copy ALL the vertices of the polygons
11121  // Loop over the polygons
11122  for (unsigned p = 0; p < n_polygons; p++)
11123  {
11124  // Get the number of vertices
11125  const unsigned n_vertices = vertices_polygons[p].size();
11126  // Loop over the vertices in the polygon
11127  for (unsigned v = 0; v < n_vertices; v++)
11128  {
11129  // Create a new "Point" to store in the input vertices
11130  Point point;
11131  // Assign the values to the "Point"
11132  point.x = vertices_polygons[p][v][0];
11133  point.y = vertices_polygons[p][v][1];
11134  // Add the "Point" to the input vertices
11135  input_vertices_convex_hull.push_back(point);
11136  } // for (v < n_vertices)
11137  } // for (p < n_polygons)
11138 
11139  // Compute the convex hull
11140  std::vector<Point> output_vertices_convex_hull =
11141  convex_hull(input_vertices_convex_hull);
11142 
11143  // Get the number of vertices in the convex hull
11144  const unsigned n_vertices_convex_hull = output_vertices_convex_hull.size();
11145 
11146  // Copy the output to the used data structures
11147  Vector<Vector<double> > vertices_convex_hull(n_vertices_convex_hull);
11148  for (unsigned i = 0; i < n_vertices_convex_hull; i++)
11149  {
11150  // Resize the data structure
11151  vertices_convex_hull[i].resize(2);
11152  // Copy the data
11153  vertices_convex_hull[i][0] = output_vertices_convex_hull[i].x;
11154  vertices_convex_hull[i][1] = output_vertices_convex_hull[i].y;
11155  } // for (i < n_vertices_convex_hull)
11156 
11157  // Loop over the vertices defining holes, work only with those
11158  // outside ALL the outer boundaries and mark those inside the convex
11159  // hull
11160  for (unsigned h = 0; h < n_input_holes; h++)
11161  {
11162  // Only work with those outside ALL the outer polygons
11163  if (is_outside_the_outer_polygons[h])
11164  {
11165  // Check if the hole is inside the convex hull
11166  const bool is_inside_convex_hull =
11167  is_point_inside_polygon_helper(vertices_convex_hull,
11168  output_holes_coordinates[h]);
11169 
11170  // If the vertex is inside the convex hull then mark it
11171  if (is_inside_convex_hull)
11172  {
11173  // Set as inside the convex hull
11174  is_inside_the_convex_hull[h] = true;
11175  } // if (is_inside_convex_hull)
11176 
11177  } // if (is_outside_the_outer_polygons[h])
11178  else
11179  {
11180  // Any vertex inside any outer polygon is inside the convex hull
11181  is_inside_the_convex_hull[h] = true;
11182  } // else if (is_outside_the_outer_polygons[h])
11183 
11184  } // for (h < n_input_holes)
11185 
11186  // Store the output holes, only (those inside an inner polygon) OR
11187  // (those outside ALL the polygons AND inside the convex hull)
11188  Vector<Vector<double> > hole_kept;
11189  for (unsigned h = 0; h < n_input_holes; h++)
11190  {
11191  // Check if the hole should be kept
11192  if ((is_inside_an_inner_polygon[h]) ||
11193  (is_outside_the_outer_polygons[h] && is_inside_the_convex_hull[h]))
11194  {
11195  // Copy the hole information
11196  hole_kept.push_back(output_holes_coordinates[h]);
11197  } // if (keep_hole[h])
11198  } // for (h < n_input_holes)
11199 
11200  // Clear the previous storage
11201  output_holes_coordinates.clear();
11202  // Set the output holes
11203  output_holes_coordinates = hole_kept;
11204 
11205  }
11206 
11207  //======================================================================
11208  // \short Sorts the polylines so they be contiguous and then we can
11209  // create a closed or open curve from them
11210  //======================================================================
11211  template<class ELEMENT>
11213  sort_polylines_helper(Vector<TriangleMeshPolyLine *>
11214  &unsorted_polylines_pt,
11215  Vector<Vector<TriangleMeshPolyLine *> >
11216  &sorted_polylines_pt)
11217  {
11218  unsigned n_unsorted_polylines = unsorted_polylines_pt.size();
11219  unsigned n_sorted_polylines = 0;
11220  unsigned curves_index = 0;
11221 
11222  // Map to know which polyline has been already sorted
11223  std::map<TriangleMeshPolyLine*, bool> done_polyline;
11224 
11225  do
11226  {
11227  // Create the list that stores the polylines and allows to introduce
11228  // polylines to the left and to the right
11229  std::list<TriangleMeshPolyLine*> sorted_polyline_list_pt;
11230  bool changes = false;
11231 
11232  // Create pointers to the left and right "side" of the sorted list of
11233  // new created TriangleMeshPolyLines
11234  TriangleMeshPolyLine* left_pt = 0;
11235  TriangleMeshPolyLine* right_pt = 0;
11236 
11237  // 1) Take the first non done polyline on the unsorted list of polylines
11238  unsigned pp = 0;
11239  bool found_root_polyline = false;
11240  while (pp < n_unsorted_polylines && !found_root_polyline)
11241  {
11242  if (!done_polyline[unsorted_polylines_pt[pp]])
11243  {found_root_polyline = true;}
11244  else
11245  {pp++;}
11246  }
11247 
11248  // Check if there are polylines to be sorted
11249  if (pp < n_unsorted_polylines)
11250  {
11251  // 2) Mark the polyline as done
11252  left_pt = right_pt = unsorted_polylines_pt[pp];
11253  done_polyline[left_pt] = true;
11254  // Increment the number of sorted polylines
11255  n_sorted_polylines++;
11256 
11257  // 3) Add this polyline to the sorted list and use it as root
11258  // to sort the other polylines
11259  sorted_polyline_list_pt.push_back(left_pt);
11260 
11261  do {
11262 
11263  changes = false;
11264 
11265  Vector<double> left_vertex(2);
11266  Vector<double> right_vertex(2);
11267 
11268  left_pt->initial_vertex_coordinate(left_vertex);
11269  right_pt->final_vertex_coordinate(right_vertex);
11270 
11271  for (unsigned i = pp+1; i < n_unsorted_polylines; i++)
11272  {
11273  TriangleMeshPolyLine *current_polyline_pt =
11274  unsorted_polylines_pt[i];
11275  if (!done_polyline[current_polyline_pt])
11276  {
11277  Vector<double> initial_vertex(2);
11278  Vector<double> final_vertex(2);
11279  current_polyline_pt->initial_vertex_coordinate(initial_vertex);
11280  current_polyline_pt->final_vertex_coordinate(final_vertex);
11281 
11282  // Compare if the current polyline should go to the left or
11283  // to the right on the sorted polyline list
11284 
11285  // Go to the left
11286  if (left_vertex == final_vertex)
11287  {
11288  left_pt = current_polyline_pt;
11289  sorted_polyline_list_pt.push_front(left_pt);
11290  done_polyline[left_pt] = true;
11291  n_sorted_polylines++;
11292 
11293  // We have added one more polyline, go for another round
11294  changes = true;
11295  }
11296  // Go to the right
11297  else if (right_vertex == initial_vertex)
11298  {
11299  right_pt = current_polyline_pt;
11300  sorted_polyline_list_pt.push_back(right_pt);
11301  done_polyline[right_pt] = true;
11302  n_sorted_polylines++;
11303 
11304  // We have added one more polyline, go for another round
11305  changes = true;
11306  }
11307  // Go to the left but it is reversed
11308  else if (left_vertex == initial_vertex)
11309  {
11310  current_polyline_pt->reverse();
11311  left_pt = current_polyline_pt;
11312  sorted_polyline_list_pt.push_front(left_pt);
11313  done_polyline[left_pt] = true;
11314  n_sorted_polylines++;
11315 
11316  // We have added one more polyline, go for another round
11317  changes = true;
11318  }
11319  // Go to the right but it is reversed
11320  else if (right_vertex == final_vertex)
11321  {
11322  current_polyline_pt->reverse();
11323  right_pt = current_polyline_pt;
11324  sorted_polyline_list_pt.push_back(right_pt);
11325  done_polyline[right_pt] = true;
11326  n_sorted_polylines++;
11327 
11328  // We have added one more polyline, go for another round
11329  changes = true;
11330  }
11331  } // if (!done_polyline[current_polyline_pt])
11332  if (changes) {break;}
11333  } // for (i < n_unsorted_polylines)
11334  }while(changes);
11335 
11336  } // if (pp < n_unsorted_polylines)
11337  else
11338  {
11339  // All the polylines are now on the sorted list of polylines
11340 #ifdef PARANOID
11341  // This case comes when it was not possible to find a root polyline
11342  // since all of them are marked as done but the number of sorted and
11343  // unsorted polylines is not the same
11344  if (!found_root_polyline)
11345  {
11346  std::stringstream err;
11347  err << "It was not possible to find a root polyline to sort the "
11348  << "others around it.\nThe number of unsorted and sorted "
11349  << "polylines is different, it means that\nnot all the "
11350  << "polylines have been sorted.\n"
11351  << "Found root polyline: ("<<found_root_polyline<<")\n"
11352  << "Sorted polylines: ("<<n_sorted_polylines<<")\n"
11353  << "Unsorted polylines: ("<<n_unsorted_polylines<<")\n";
11354  throw OomphLibError(err.str(),"TriangleMesh::sort_polylines_helper()",
11355  OOMPH_EXCEPTION_LOCATION);
11356  }
11357 #endif
11358  }
11359 
11360  // Create the storage for the new sorted polylines and copy them on the
11361  // vector structure for sorted polylines
11362  unsigned n_sorted_polyline_on_list = sorted_polyline_list_pt.size();
11363 
11364  // Create the temporal vector that stores the sorted polylines
11365  Vector<TriangleMeshPolyLine *>
11366  tmp_sorted_polylines(n_sorted_polyline_on_list);
11367  unsigned counter = 0;
11368 
11369  std::list<TriangleMeshPolyLine*>::iterator it_polyline;
11370  for (it_polyline = sorted_polyline_list_pt.begin();
11371  it_polyline != sorted_polyline_list_pt.end();
11372  it_polyline++)
11373  {
11374  tmp_sorted_polylines[counter] = *it_polyline;
11375  counter++;
11376  }
11377 
11378  sorted_polylines_pt.push_back(tmp_sorted_polylines);
11379 
11380  ++curves_index;
11381 
11382  }while(n_sorted_polylines < n_unsorted_polylines);
11383 
11384 #ifdef PARANOID
11385  // Verify that the number of polylines on the sorted list is the same
11386  // as the number of polylines on the unsorted list
11387  if (n_sorted_polylines != n_unsorted_polylines)
11388  {
11389  std::stringstream err;
11390  err << "The number of polylines on the unsorted and sorted vectors"
11391  << " is different,\n"
11392  << "it means that not all the polylines have been sorted.\n"
11393  << "Sorted polylines: "<<n_sorted_polylines
11394  << "\nUnsorted polylines: "<<n_unsorted_polylines;
11395  throw OomphLibError(err.str(), "TriangleMesh::sort_polylines_helper()",
11396  OOMPH_EXCEPTION_LOCATION);
11397  }
11398 #endif
11399 
11400  }
11401 
11402  //======================================================================
11403  // \short Creates the shared boundaries
11404  //======================================================================
11405  template<class ELEMENT>
11407  OomphCommunicator* comm_pt,
11408  const Vector<unsigned> &element_domain,
11409  const Vector<GeneralisedElement*> &backed_up_el_pt,
11410  const Vector<FiniteElement*> &backed_up_f_el_pt,
11411  std::map<Data*,std::set<unsigned> > &processors_associated_with_data,
11412  const bool& overrule_keep_as_halo_element_status)
11413  {
11414  // Storage for number of processors and current processor
11415  const unsigned nproc = comm_pt->nproc();
11416  const unsigned my_rank = comm_pt->my_rank();
11417 
11418  // Storage for all the halo elements on all processors
11419  // halo_element[iproc][jproc][ele_number]
11420  // Stores the "ele_number"-th halo element of processor "iproc" with
11421  // processor "jproc"
11422  Vector<Vector<Vector<GeneralisedElement*> > > halo_element_pt(nproc);
11423  // Create complete storage for the halo_element_pt container
11424  for (unsigned iproc = 0; iproc < nproc; iproc++)
11425  {halo_element_pt[iproc].resize(nproc);}
11426 
11427  // Store the global index of the element, used to check for possible
11428  // misclassification of halo elements in the above container
11429  // (halo_element_pt)
11430  std::map<GeneralisedElement*, unsigned> element_to_global_index;
11431 
11432  // Get the halo elements on all processors
11433  this->get_halo_elements_on_all_procs(nproc, element_domain,
11434  backed_up_el_pt,
11435  processors_associated_with_data,
11436  overrule_keep_as_halo_element_status,
11437  element_to_global_index,
11438  halo_element_pt);
11439 
11440  // Resize the shared polylines container
11441  flush_shared_boundary_polyline_pt();
11442  Shared_boundary_polyline_pt.resize(nproc);
11443 
11444  // Create a set that store only the elements that will be kept in
11445  // the processor as nonhalo element, those whose element_domains is
11446  // equal to my_rank. This set is used when creating the shared
11447  // polylines and identify the connections to the original boundaries
11448  std::set<FiniteElement*> element_in_processor_pt;
11449  const unsigned n_ele = backed_up_f_el_pt.size();
11450  for (unsigned e = 0; e < n_ele; e++)
11451  {
11452  if (element_domain[e] == my_rank)
11453  {
11454  element_in_processor_pt.insert(backed_up_f_el_pt[e]);
11455  } // if (element_domain[e] == my_rank)
11456  } // for (e < n_elex)
11457 
11458  // Look for elements edges that may lie on internal boundaries
11459  // If that is the case then relate the face with the boundary on
11460  // which it lies
11461  std::map<std::pair<Node*,Node*>, unsigned> elements_edges_on_boundary;
11462  this->get_element_edges_on_boundary(elements_edges_on_boundary);
11463 
11464  // Now we have all the halo elements on all processors. Use the
11465  // edges shared by the halo elements to create the shared boundaries.
11466  this->create_polylines_from_halo_elements_helper(element_domain,
11467  element_to_global_index,
11468  element_in_processor_pt,
11469  halo_element_pt,
11470  elements_edges_on_boundary,
11471  Shared_boundary_polyline_pt);
11472 
11473  }
11474 
11475  //======================================================================
11476  /// \short Creates the halo elements on all processors
11477  /// Gets the halo elements on all processors, these elements are then used
11478  /// on the function that computes the shared boundaries among the processors
11479  //======================================================================
11480  template<class ELEMENT>
11482  const unsigned &nproc, const Vector<unsigned> &element_domain,
11483  const Vector<GeneralisedElement*> &backed_up_el_pt,
11484  std::map<Data*,std::set<unsigned> > &processors_associated_with_data,
11485  const bool&overrule_keep_as_halo_element_status,
11486  std::map<GeneralisedElement*, unsigned> &element_to_global_index,
11487  Vector<Vector<Vector<GeneralisedElement*> > > &output_halo_elements_pt)
11488  {
11489  const unsigned n_ele = backed_up_el_pt.size();
11490 
11491  // Loop over all the processors
11492  for (unsigned iproc = 0; iproc < nproc; iproc++)
11493  {
11494  // Boolean to know which elements has been already added to the
11495  // halo scheme on "iproc" processor
11496  Vector<std::map<GeneralisedElement*, bool> > already_added(nproc);
11497 
11498  // Loop over all backed up elements
11499  for (unsigned e=0;e<n_ele;e++)
11500  {
11501  // Get element and its domain
11502  GeneralisedElement* el_pt=backed_up_el_pt[e];
11503  unsigned el_domain=element_domain[e];
11504 
11505  // If element is NOT located on "iproc" processor then check if it is
11506  // halo with "el_domain" processor
11507  if (el_domain!=iproc)
11508  {
11509  // If this current mesh has been told to keep all elements as halos,
11510  // OR the element itself knows that it must be kept then
11511  // keep it
11512  if ((this->Keep_all_elements_as_halos) ||
11513  (el_pt->must_be_kept_as_halo()))
11514  {
11515  if (!overrule_keep_as_halo_element_status)
11516  {
11517  // Add as halo element whose non-halo counterpart is
11518  // located on processor "el_domain"
11519  if (!already_added[el_domain][el_pt])
11520  {
11521  output_halo_elements_pt[iproc][el_domain].push_back(el_pt);
11522  already_added[el_domain][el_pt] = true;
11523  element_to_global_index[el_pt] = e;
11524  }
11525  }
11526  }
11527  // Otherwise: Is one of the nodes associated with other processor?
11528  else
11529  {
11530  //Can only have nodes if this is a finite element
11531  FiniteElement* finite_el_pt = dynamic_cast<FiniteElement*>(el_pt);
11532  if(finite_el_pt!=0)
11533  {
11534  unsigned n_node = finite_el_pt->nnode();
11535  for (unsigned n=0;n<n_node;n++)
11536  {
11537  Node* nod_pt=finite_el_pt->node_pt(n);
11538 
11539  // Keep element?
11540  std::set<unsigned>::iterator it =
11541  processors_associated_with_data[nod_pt].find(iproc);
11542  if (it!=processors_associated_with_data[nod_pt].end())
11543  {
11544  // Add as root halo element whose non-halo counterpart is
11545  // located on processor "el_domain"
11546  if (!already_added[el_domain][el_pt])
11547  {
11548  output_halo_elements_pt[iproc][el_domain].push_back(el_pt);
11549  already_added[el_domain][el_pt] = true;
11550  element_to_global_index[el_pt] = e;
11551  }
11552  // Now break out of loop over nodes
11553  break;
11554  } // if (it!=processors_associated_with_data[nod_pt].end())
11555  } // for (n < n_node)
11556  } // if (finite_el_pt!=0)
11557  } // else (this->Keep_all_elements_as_halos)
11558  } // if (el_domain!=iproc)
11559  } // for (e < nele)
11560  } // for (iproc < nproc)
11561 
11562  }
11563 
11564  //====================================================================
11565  // \short Get the element edges (pair of nodes, edges) that lie
11566  // on a boundary (used to mark shared boundaries that lie on
11567  // internal boundaries)
11568  //====================================================================
11569  template <class ELEMENT>
11571  std::map<std::pair<Node*,Node*>, unsigned> &element_edges_on_boundary)
11572  {
11573  // The number of original boundaries
11574  const unsigned nbound = this->nboundary();
11575  // Loop over the boundaries
11576  for (unsigned b = 0; b < nbound; b++)
11577  {
11578  // Keep track of the pair of nodes done
11579  std::map<std::pair<Node*, Node*>, bool> edge_done;
11580  // Get the number of elements on the boundary
11581  const unsigned nbound_ele = this->nboundary_element(b);
11582  for (unsigned e = 0; e < nbound_ele; e++)
11583  {
11584  // Get the boundary bulk element
11585  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
11586  // Get the face index
11587  int face_index = this->face_index_at_boundary(b, e);
11588  // Create the face element
11589  FiniteElement* face_ele_pt =
11590  new DummyFaceElement<ELEMENT> (bulk_ele_pt, face_index);
11591  // Get the number of nodes on the face element
11592  const unsigned nnodes = face_ele_pt->nnode();
11593  // Get the first and last node
11594  Node* first_node_pt = face_ele_pt->node_pt(0);
11595  Node* last_node_pt = face_ele_pt->node_pt(nnodes-1);
11596 
11597  // Create the pair to store the nodes
11598  std::pair<Node*,Node*> edge =
11599  std::make_pair(first_node_pt, last_node_pt);
11600 
11601  // Has the edge been included
11602  if (!edge_done[edge])
11603  {
11604  // Mark the edge as done
11605  edge_done[edge] = true;
11606 
11607  // Create the reversed version and mark it as done too
11608  std::pair<Node*,Node*> inv_edge =
11609  std::make_pair(last_node_pt, first_node_pt);
11610 
11611  // Mark the reversed edge as done
11612  edge_done[inv_edge] = true;
11613 
11614  // Mark the edge to belong to boundary b
11615  element_edges_on_boundary[edge] = b;
11616  } // if (!edge_done[edge])
11617 
11618  // Free the memory allocated for the face element
11619  delete face_ele_pt;
11620  face_ele_pt = 0;
11621 
11622  } // for (e < nbound_ele)
11623 
11624  } // for (b < nbound)
11625 
11626  }
11627 
11628  // ======================================================================
11629  // \short Creates polylines from the intersection of halo elements on
11630  // all processors. The new polylines define the shared boundaries in
11631  // the domain This method computes the polylines on ALL processors,
11632  // that is why the three dimensions in the structure
11633  // output_polylines_pt[iproc][ncurve][npolyline]
11634  // ======================================================================
11635  template<class ELEMENT>
11637  const Vector<unsigned> &element_domain,
11638  std::map<GeneralisedElement*, unsigned> &element_to_global_index,
11639  std::set<FiniteElement*> &element_in_processor_pt,
11640  Vector<Vector<Vector<GeneralisedElement*> > > &input_halo_elements,
11641  std::map<std::pair<Node*,Node*>, unsigned> &elements_edges_on_boundary,
11642  Vector<Vector<Vector<TriangleMeshPolyLine *> > > &output_polylines_pt)
11643  {
11644  const unsigned nproc = this->communicator_pt()->nproc();
11645  const unsigned my_rank = this->communicator_pt()->my_rank();
11646 
11647  // ---------------------------------------------------------------
11648  // Get the edges shared between each pair of processors
11649  // ---------------------------------------------------------------
11650 
11651  // Storage for the edges (pair of nodes) shared between a pair of
11652  // processors
11653  Vector<Vector<Vector<std::pair<Node*,Node*> > > > edges(nproc);
11654 
11655  // Each edge is associated to two elements, a haloi (halo element
11656  // in processors i) and a haloj (halo element in processors j)
11657  Vector<Vector<Vector<Vector<FiniteElement*> > > > edge_element_pt(nproc);
11658 
11659  // Each edge is associated to two elements, a haloi and a haloj,
11660  // the edge was created from a given face from each element, the
11661  // haloi face is stored at [0], the haloj face is stored at [1]
11662  Vector<Vector<Vector<Vector<int> > > > edge_element_face(nproc);
11663 
11664  // Store the possible internal boundary id associated to each edge
11665  // (-1 if there is no association). Some edges may overlap an
11666  // internal boundary (and only internal boundaries)
11667  Vector<Vector<Vector<int> > > edge_boundary(nproc);
11668 
11669  // Mark those edges (pair of nodes overlapped by a shared boundary)
11670  std::map<std::pair<Node*,Node*>, bool> overlapped_edge;
11671 
11672  // Resize the containers, they store info. for each pair of
11673  // processors
11674 
11675  // First resize the global container
11676  Shared_boundaries_ids.resize(nproc);
11677  for (unsigned j = 0 ; j < nproc; j++)
11678  {
11679  edges[j].resize(nproc);
11680  edge_element_pt[j].resize(nproc);
11681  edge_element_face[j].resize(nproc);
11682  edge_boundary[j].resize(nproc);
11683 
11684  // Resize the global container for shared boundaries ids
11685  Shared_boundaries_ids[j].resize(nproc);
11686 
11687  } // for (j < nproc)
11688 
11689  // Take the halo elements of processor "iproc" and compare their
11690  // edges with halo elements of other processors (except itself)
11691  for (unsigned iproc = 0; iproc < nproc; iproc++)
11692  {
11693  // Take the halo elements of processor iproc and compare with
11694  // other processors
11695  // Start from the iproc + 1,
11696  // 1) To avoid comparing with itself,
11697  // 2) To avoid generation of repeated boundaries
11698  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
11699  {
11700  // **************************************************************
11701  // FIRST PART
11702  // 1) Get the halo elements of processor "iproc" with processor
11703  // "jproc"
11704  // 2) Get the halo elements of processor "jproc" with processor
11705  // "iproc"
11706  // 3) Compare their edges and those that match are the ones that
11707  // define the shared boundaries
11708  // **************************************************************
11709 
11710  // Storage for halo elements
11711  Vector<GeneralisedElement*> halo_elements_iproc_with_jproc;
11712  Vector<GeneralisedElement*> halo_elements_jproc_with_iproc;
11713 
11714  // Get the halo elements of "iproc" with "jproc"
11715  halo_elements_iproc_with_jproc = input_halo_elements[iproc][jproc];
11716 
11717  // If there are halo elements then there are shared boundaries
11718  const unsigned nhalo_elements_iproc_with_jproc =
11719  halo_elements_iproc_with_jproc.size();
11720 // DEBP(nhalo_elements_iproc_with_jproc);
11721  if (nhalo_elements_iproc_with_jproc > 0)
11722  {
11723  // Get the halo elements of "jproc" with "iproc"
11724  halo_elements_jproc_with_iproc = input_halo_elements[jproc][iproc];
11725 
11726  // If there are halo elements then there are shared
11727  // boundaries
11728  const unsigned nhalo_elements_jproc_with_iproc =
11729  halo_elements_jproc_with_iproc.size();
11730 // DEBP(nhalo_elements_jproc_with_iproc);
11731 #ifdef PARANOID
11732  if (nhalo_elements_jproc_with_iproc == 0)
11733  {
11734  // If there are halo elements of iproc with jproc there
11735  // MUST be halo elements on the other way round, not
11736  // necessary the same but at least one
11737  std::stringstream err;
11738  err <<"There are no halo elements from processor ("<<jproc<<") "
11739  <<"with processor ("<<iproc<<").\n"
11740  <<"This is strange since there are halo elements from "
11741  <<"processor ("<<iproc<<") with processor ("<<jproc<<").\n"
11742  <<"Number of halo elements from ("<<iproc<<") to ("
11743  <<jproc<<") : ("<< nhalo_elements_iproc_with_jproc<<")\n"
11744  <<"Number of halo elements from ("<<jproc<<") to ("
11745  <<iproc<<") : ("<< nhalo_elements_jproc_with_iproc<<")\n";
11746  throw OomphLibError(err.str(),
11747  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11748  OOMPH_EXCEPTION_LOCATION);
11749  }
11750 #endif
11751  // The edges are defined as pair of nodes
11752  Vector<Node*> halo_edges_iproc;
11753  unsigned halo_edges_counter_iproc = 0;
11754  Vector<Node*> halo_edges_jproc;
11755  unsigned halo_edges_counter_jproc = 0;
11756 
11757  // Map to associate the edge with the element used to create it
11758  std::map<std::pair<Node*,Node*>,FiniteElement*> edgesi_to_element_pt;
11759 
11760  // Map to associated the edge with the face number of the
11761  // element that created it
11762  std::map<std::pair<std::pair<Node*,Node*>, FiniteElement*>, int>
11763  edgesi_element_pt_to_face_index;
11764 
11765  // Map to associate the edge with the element used to create it
11766  std::map<std::pair<Node*,Node*>,FiniteElement*> edgesj_to_element_pt;
11767 
11768  // Map to associated the edge with the face number of the
11769  // element that created it
11770  std::map<std::pair<std::pair<Node*,Node*>, FiniteElement*>, int>
11771  edgesj_element_pt_to_face_index;
11772 
11773  // **************************************************************
11774  // 1.1) Store the edges of the "iproc" halo elements
11775  // **************************************************************
11776  // Go throught halo elements on "iproc" processor
11777  for (unsigned ih = 0; ih < nhalo_elements_iproc_with_jproc; ih++)
11778  {
11779 #ifdef PARANOID
11780  unsigned e =
11781  element_to_global_index[halo_elements_iproc_with_jproc[ih]];
11782  // Only work with halo elements inside the "jproc" processor
11783  if (element_domain[e] != jproc)
11784  {
11785  // There was a problem on the ihalo-jhalo classification
11786  std::stringstream err;
11787  err << "There was a problem on the ihalo-jhalo classification.\n"
11788  << "One of the elements, (the one with the ("<<e<<")-th "
11789  << "index ) is not on the ("<<jproc<<")-th processor\n"
11790  << "but it was stored as a halo element of processor ("
11791  << iproc<<") with processor ("<<jproc<<").\n";
11792  throw OomphLibError(
11793  err.str(),
11794  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11795  OOMPH_EXCEPTION_LOCATION);
11796  }
11797 #endif
11798 
11799  FiniteElement* el_pt =
11800  dynamic_cast<FiniteElement*>(halo_elements_iproc_with_jproc[ih]);
11801 
11802  if (el_pt==0)
11803  {
11804  std::stringstream err;
11805  err << "The halo element ("<<ih<<") could not be casted to the "
11806  << "FiniteElement type.\n";
11807  throw OomphLibError(
11808  err.str(),
11809  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11810  OOMPH_EXCEPTION_LOCATION);
11811  }
11812 
11813 #ifdef PARANOID
11814  // Number of nodes on this element
11815  const unsigned n_nodes = el_pt->nnode();
11816 
11817  // The number of nodes on every element should be at least
11818  // three since we are going to work with the cornes nodes,
11819  // the ones with index 0, 1 and 2
11820  if (n_nodes<3)
11821  {
11822  std::stringstream err;
11823  err << "The number of nodes of the "<<ih<<"-th halo element is"
11824  << " ("<< n_nodes << ").\nWe can not work with triangle "
11825  << "elements with less than three nodes\n";
11826  throw OomphLibError(err.str(),
11827  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11828  OOMPH_EXCEPTION_LOCATION);
11829  }
11830 #endif
11831 
11832  // Get the corner nodes, the first three nodes
11833  Node *first_node_pt = el_pt->node_pt(0);
11834  Node *second_node_pt = el_pt->node_pt(1);
11835  Node *third_node_pt = el_pt->node_pt(2);
11836 
11837  // Store the edges
11838  halo_edges_iproc.push_back(first_node_pt);
11839  halo_edges_iproc.push_back(second_node_pt);
11840  halo_edges_counter_jproc++;
11841 
11842  halo_edges_iproc.push_back(second_node_pt);
11843  halo_edges_iproc.push_back(third_node_pt);
11844  halo_edges_counter_jproc++;
11845 
11846  halo_edges_iproc.push_back(third_node_pt);
11847  halo_edges_iproc.push_back(first_node_pt);
11848  halo_edges_counter_jproc++;
11849 
11850  // Store the info. of the element used to create these edges
11851  std::pair<Node*, Node*> edge1 =
11852  std::make_pair(first_node_pt, second_node_pt);
11853  edgesi_to_element_pt[edge1] = el_pt;
11854 
11855  std::pair<Node*, Node*> edge2 =
11856  std::make_pair(second_node_pt, third_node_pt);
11857  edgesi_to_element_pt[edge2] = el_pt;
11858 
11859  std::pair<Node*, Node*> edge3 =
11860  std::make_pair(third_node_pt, first_node_pt);
11861  edgesi_to_element_pt[edge3] = el_pt;
11862 
11863  // Store the face index of the edge in the element
11864  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele1 =
11865  std::make_pair(edge1, el_pt);
11866  edgesi_element_pt_to_face_index[edge_ele1] = 2;
11867 
11868  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele2 =
11869  std::make_pair(edge2, el_pt);
11870  edgesi_element_pt_to_face_index[edge_ele2] = 0;
11871 
11872  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele3 =
11873  std::make_pair(edge3, el_pt);
11874  edgesi_element_pt_to_face_index[edge_ele3] = 1;
11875 
11876  } // for (ih < nhalo_elements_iproc_with_jproc)
11877 
11878  // **************************************************************
11879  // 1.2) Store the edges of the "jproc" halo elements
11880  // **************************************************************
11881  // Go throught halo elements on "jproc" processor
11882  for (unsigned jh = 0; jh < nhalo_elements_jproc_with_iproc; jh++)
11883  {
11884 #ifdef PARANOID
11885  unsigned e =
11886  element_to_global_index[halo_elements_jproc_with_iproc[jh]];
11887  // Only work with halo elements inside the "jproc" processor
11888  if (element_domain[e] != iproc)
11889  {
11890  // There was a problem on the jhalo-ihalo classification
11891  std::stringstream err;
11892  err << "There was a problem on the jhalo-ihalo classification.\n"
11893  << "One of the elements, (the one with the ("<<e<<")-th "
11894  << "index ) is not on the ("<<iproc<<")-th processor\n"
11895  << "but it was stored as a halo element of processor ("
11896  << jproc<<") with processor ("<<iproc<<").\n";
11897  throw OomphLibError(
11898  err.str(),
11899  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11900  OOMPH_EXCEPTION_LOCATION);
11901  }
11902 #endif
11903 
11904  FiniteElement* el_pt =
11905  dynamic_cast<FiniteElement*>(halo_elements_jproc_with_iproc[jh]);
11906  if (el_pt==0)
11907  {
11908  std::stringstream err;
11909  err << "The halo element ("<<jh<<") could not be casted to the "
11910  << "FiniteElement type.\n";
11911  throw OomphLibError(
11912  err.str(),
11913  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11914  OOMPH_EXCEPTION_LOCATION);
11915  }
11916 
11917 #ifdef PARANOID
11918  // Number of nodes on this element
11919  const unsigned n_nodes = el_pt->nnode();
11920 
11921  // The number of nodes on every element should be at least
11922  // three since we are going to work with the cornes nodes,
11923  // the ones with index 0, 1 and 2
11924  if (n_nodes<3)
11925  {
11926  std::stringstream err;
11927  err << "The number of nodes of the "<<jh<<"-th halo element is"
11928  << " ("<< n_nodes << ").\nWe can not work with triangle "
11929  << "elements with less than three nodes\n";
11930  throw OomphLibError(err.str(),
11931  "TriangleMesh::create_polylines_from_halo_elements_helper()",
11932  OOMPH_EXCEPTION_LOCATION);
11933  }
11934 #endif
11935 
11936  // Get the nodes pointers
11937  Node *first_node_pt = el_pt->node_pt(0);
11938  Node *second_node_pt = el_pt->node_pt(1);
11939  Node *third_node_pt = el_pt->node_pt(2);
11940 
11941  // Store the edges
11942  halo_edges_jproc.push_back(first_node_pt);
11943  halo_edges_jproc.push_back(second_node_pt);
11944  halo_edges_counter_iproc++;
11945 
11946  halo_edges_jproc.push_back(second_node_pt);
11947  halo_edges_jproc.push_back(third_node_pt);
11948  halo_edges_counter_iproc++;
11949 
11950  halo_edges_jproc.push_back(third_node_pt);
11951  halo_edges_jproc.push_back(first_node_pt);
11952  halo_edges_counter_iproc++;
11953 
11954  // Store the info. of the element used to create these edges
11955  std::pair<Node*, Node*> edge1 =
11956  std::make_pair(first_node_pt, second_node_pt);
11957  edgesj_to_element_pt[edge1] = el_pt;
11958 
11959  std::pair<Node*, Node*> edge2 =
11960  std::make_pair(second_node_pt, third_node_pt);
11961  edgesj_to_element_pt[edge2] = el_pt;
11962 
11963  std::pair<Node*, Node*> edge3 =
11964  std::make_pair(third_node_pt, first_node_pt);
11965  edgesj_to_element_pt[edge3] = el_pt;
11966 
11967  // Store the face index of the edge in the element
11968  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele1 =
11969  std::make_pair(edge1, el_pt);
11970  edgesj_element_pt_to_face_index[edge_ele1] = 2;
11971 
11972  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele2 =
11973  std::make_pair(edge2, el_pt);
11974  edgesj_element_pt_to_face_index[edge_ele2] = 0;
11975 
11976  std::pair<std::pair<Node*, Node*>, FiniteElement*> edge_ele3 =
11977  std::make_pair(edge3, el_pt);
11978  edgesj_element_pt_to_face_index[edge_ele3] = 1;
11979 
11980  } // for (jh < nhalo_elements_jproc_with_iproc)
11981 
11982  // ***************************************************************
11983  // SECOND PART
11984  // 1) We already have the information of the edges on the iproc
11985  // halo and jproc halo elements
11986  // 2) Identify the shared edges to create the shared boundaries
11987  // (Only store the information but do not create the polyline)
11988  // ***************************************************************
11989 
11990  // Get the number of edges from each processor
11991  unsigned nhalo_iedges = halo_edges_iproc.size();
11992  unsigned nhalo_jedges = halo_edges_jproc.size();
11993 
11994  // Start comparing the edges to check which of those are
11995  // shared between the "ihalo_edge" and the "jhalo_edge"
11996  for (unsigned ihe = 0; ihe < nhalo_iedges; ihe+=2)
11997  {
11998  // Get the ihe-th edge (pair of nodes)
11999  Vector<Node*> ihalo_edge(2);
12000  ihalo_edge[0] = halo_edges_iproc[ihe];
12001  ihalo_edge[1] = halo_edges_iproc[ihe+1];
12002 
12003  // Create the pair that defines the edge
12004  std::pair<Node*,Node*> tmp_edge = std::make_pair(ihalo_edge[0],
12005  ihalo_edge[1]);
12006 
12007  // Check if the edge lies on a boundary (default values is
12008  // -1 for no association with an internal boundary)
12009  int edge_boundary_id = -1;
12010  {
12011  std::map<std::pair<Node*,Node*>,unsigned >::iterator it;
12012  it = elements_edges_on_boundary.find(tmp_edge);
12013  // If the edges lie on a boundary then get the boundary id
12014  // on which the edges lie
12015  if (it != elements_edges_on_boundary.end())
12016  {
12017  // Assign the internal boundary id associated with the
12018  // edge
12019  edge_boundary_id = (*it).second;
12020  }
12021  else
12022  {
12023  // Look for the reversed version of the edge (the nodes
12024  // inverted)
12025  std::pair<Node*,Node*> rtmp_edge = std::make_pair(ihalo_edge[1],
12026  ihalo_edge[0]);
12027  it = elements_edges_on_boundary.find(rtmp_edge);
12028  if (it != elements_edges_on_boundary.end())
12029  {
12030  // Assign the internal boundary id associated with the
12031  // edge
12032  edge_boundary_id = (*it).second;
12033  }
12034  }
12035  }
12036 
12037  // Go through the jhalo_edge and compare with the
12038  // ihalo_edge
12039  for (unsigned jhe = 0; jhe < nhalo_jedges; jhe+=2)
12040  {
12041  // Get the jhe-th edge (pair of nodes)
12042  Vector<Node*> jhalo_edge(2);
12043  jhalo_edge[0] = halo_edges_jproc[jhe];
12044  jhalo_edge[1] = halo_edges_jproc[jhe+1];
12045 
12046  // Comparing pointer of nodes
12047  if (ihalo_edge[0] == jhalo_edge[0] &&
12048  ihalo_edge[1] == jhalo_edge[1])
12049  {
12050  // Create the edge (both nodes that make the edge)
12051  std::pair<Node*, Node*> new_edge =
12052  std::make_pair(ihalo_edge[0], ihalo_edge[1]);
12053 
12054  // Get the elements involved in the creation of the
12055  // edge to check that there are elements associated to
12056  // the edge
12057  FiniteElement* haloi_ele_pt = 0;
12058  haloi_ele_pt = edgesi_to_element_pt[new_edge];
12059  FiniteElement* haloj_ele_pt = 0;
12060  haloj_ele_pt = edgesj_to_element_pt[new_edge];
12061 
12062  // Verify that there is an element associated with it
12063  if (haloi_ele_pt == 0 || haloj_ele_pt == 0)
12064  {
12065  std::stringstream err;
12066  err << "There is no associated elements with the new "
12067  << "shared boundary. This is an storing problem,\n"
12068  << "possibly related with a memory leak problem!!!\n"
12069  << "The nodes that compound the edge are these:\n"
12070  << "On processor ("<<iproc<<"):\n"
12071  << "("<<ihalo_edge[0]->x(0)<<", "<<ihalo_edge[0]->x(1)
12072  <<") and ("<<ihalo_edge[1]->x(0)<<", "
12073  <<ihalo_edge[1]->x(1)<<")\n\n"
12074  << "On processor ("<<jproc<<"):\n"
12075  << "("<<jhalo_edge[0]->x(0)<<", "<<jhalo_edge[0]->x(1)
12076  <<") and ("<<jhalo_edge[1]->x(0)<<", "
12077  <<jhalo_edge[1]->x(1)<<")\n\n"
12078  << "The nodes coordinates should be the same!!!\n";
12079  throw OomphLibError(err.str(),
12080  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12081  OOMPH_EXCEPTION_LOCATION);
12082  }
12083 
12084  // Store the edge
12085  edges[iproc][jproc].push_back(new_edge);
12086 
12087  // Is the edge overlapped by a shared boundary
12088  if (edge_boundary_id >= 0)
12089  {
12090  // Mark the edge as overlapped
12091  overlapped_edge[new_edge] = true;
12092 
12093  // Also mark the reversed edge
12094  std::pair<Node*, Node*> rev_new_edge =
12095  std::make_pair(ihalo_edge[1], ihalo_edge[0]);
12096 
12097  // Mark the edge as overlapped
12098  overlapped_edge[rev_new_edge] = true;
12099 
12100  } // if (edge_boundary_id >= 0)
12101 
12102  // Store the internal boundary id (default -1)
12103  // associated to the edge
12104  edge_boundary[iproc][jproc].push_back(edge_boundary_id);
12105 
12106  // Store the two elements associated with the edge
12107  Vector<FiniteElement*> tmp_elements_pt;
12108  tmp_elements_pt.push_back(haloi_ele_pt);
12109  tmp_elements_pt.push_back(haloj_ele_pt);
12110 
12111  // Associate the edge with the elements that gave rise to it
12112  edge_element_pt[iproc][jproc].push_back(tmp_elements_pt);
12113 
12114  // Get the face index on each element that gave rise to
12115  // the edge
12116 
12117  // .. first create the pair (edge, finite_element)
12118  std::pair<std::pair<Node*,Node*>, FiniteElement*>
12119  edge_elementi_pair = make_pair(new_edge, haloi_ele_pt);
12120 
12121  std::pair<std::pair<Node*,Node*>, FiniteElement*>
12122  edge_elementj_pair = make_pair(new_edge, haloj_ele_pt);
12123 
12124  // Set default values to later check if values were
12125  // read from the map structure
12126  int face_index_haloi_ele = -1;
12127  face_index_haloi_ele =
12128  edgesi_element_pt_to_face_index[edge_elementi_pair];
12129  int face_index_haloj_ele = -1;
12130  face_index_haloj_ele =
12131  edgesj_element_pt_to_face_index[edge_elementj_pair];
12132  // Verify that there is an element associated with it
12133  if (face_index_haloi_ele == -1 || face_index_haloj_ele == -1)
12134  {
12135  std::stringstream err;
12136  err << "There is no associated face indexes to the"
12137  << "elements that gave\nrise to the shared edge\n"
12138  << "The nodes that compound the edge are these:\n"
12139  << "On processor ("<<iproc<<"):\n"
12140  << "("<<ihalo_edge[0]->x(0)<<", "<<ihalo_edge[0]->x(1)
12141  <<") and ("<<ihalo_edge[1]->x(0)<<", "
12142  <<ihalo_edge[1]->x(1)<<")\n\n"
12143  << "On processor ("<<jproc<<"):\n"
12144  << "("<<jhalo_edge[0]->x(0)<<", "<<jhalo_edge[0]->x(1)
12145  <<") and ("<<jhalo_edge[1]->x(0)<<", "
12146  <<jhalo_edge[1]->x(1)<<")\n\n"
12147  << "The nodes coordinates should be the same!!!\n";
12148  throw OomphLibError(err.str(),
12149  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12150  OOMPH_EXCEPTION_LOCATION);
12151  } // if (face_index_haloi_ele == -1 ||
12152  // face_index_haloj_ele == -1)
12153 
12154  // Get the face indexes from the map structure
12155  Vector<int> tmp_edge_element_face_index;
12156  tmp_edge_element_face_index.push_back(face_index_haloi_ele);
12157  tmp_edge_element_face_index.push_back(face_index_haloj_ele);
12158  // Store the face indexes
12159  edge_element_face[iproc][jproc].
12160  push_back(tmp_edge_element_face_index);
12161 
12162  break; // break for (jhe < nhalo_jedges) since edge
12163  // found
12164 
12165  } // if (ihalo_edge[0] == jhalo_edge[0] &&
12166  // ihalo_edge[1] == jhalo_edge[1])
12167  // Comparing nodes pointers
12168  else if (ihalo_edge[0] == jhalo_edge[1] &&
12169  ihalo_edge[1] == jhalo_edge[0])
12170  {
12171  // Create the edge (both nodes that make the edge)
12172  std::pair<Node*, Node*> new_edge =
12173  std::make_pair(ihalo_edge[0], ihalo_edge[1]);
12174 
12175  // Get the elements involved in the creation of the
12176  // edge
12177  FiniteElement* haloi_ele_pt = 0;
12178  haloi_ele_pt = edgesi_to_element_pt[new_edge];
12179 
12180  FiniteElement* haloj_ele_pt = 0;
12181  // Create the edge (reversed, that is how it was
12182  // originally stored)
12183  std::pair<Node*, Node*> new_edge_reversed =
12184  std::make_pair(jhalo_edge[0], jhalo_edge[1]);
12185  haloj_ele_pt = edgesj_to_element_pt[new_edge_reversed];
12186 
12187  // Verify that there is an element associated with it
12188  if (haloi_ele_pt == 0 || haloj_ele_pt == 0)
12189  {
12190  std::stringstream err;
12191  err << "There is no associated elements with the new "
12192  << "shared boundary (reversed version). This is an "
12193  << "storing problem, possibly related with a memory "
12194  << "leak problem!!!\n"
12195  << "The nodes that compound the edge are these:\n"
12196  << "On processor ("<<iproc<<"):\n"
12197  << "("<<ihalo_edge[0]->x(0)<<", "<<ihalo_edge[0]->x(1)
12198  <<") and ("<<ihalo_edge[1]->x(0)<<", "
12199  <<ihalo_edge[1]->x(1)<<")\n\n"
12200  << "On processor ("<<jproc<<"):\n"
12201  << "("<<jhalo_edge[0]->x(0)<<", "<<jhalo_edge[0]->x(1)
12202  <<") and ("<<jhalo_edge[1]->x(0)<<", "
12203  <<jhalo_edge[1]->x(1)<<")\n\n"
12204  << "The nodes coordinates should be the same!!!\n";
12205  throw OomphLibError(err.str(),
12206  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12207  OOMPH_EXCEPTION_LOCATION);
12208  }
12209 
12210  // Store the edge
12211  edges[iproc][jproc].push_back(new_edge);
12212 
12213  // Is the edge overlapped by a shared boundary
12214  if (edge_boundary_id >= 0)
12215  {
12216  // Mark the edge as overlapped
12217  overlapped_edge[new_edge] = true;
12218 
12219  // Also mark the reversed edge
12220  std::pair<Node*, Node*> rev_new_edge =
12221  std::make_pair(ihalo_edge[1], ihalo_edge[0]);
12222 
12223  // Mark the edge as overlapped
12224  overlapped_edge[rev_new_edge] = true;
12225  } // if (edge_boundary_id >= 0)
12226 
12227  // Store the internal boundary id (default -1)
12228  // associated to the edge
12229  edge_boundary[iproc][jproc].push_back(edge_boundary_id);
12230 
12231  // Store the two elements associated with the edge
12232  Vector<FiniteElement*> tmp_elements_pt;
12233  tmp_elements_pt.push_back(haloi_ele_pt);
12234  tmp_elements_pt.push_back(haloj_ele_pt);
12235 
12236  // Associate the edge with the elements that gave rise to it
12237  edge_element_pt[iproc][jproc].push_back(tmp_elements_pt);
12238 
12239  // Get the face index on each element that gave rise to
12240  // the edge
12241 
12242  // .. first create the pair (edge, finite_element)
12243  std::pair<std::pair<Node*,Node*>, FiniteElement*>
12244  edge_elementi_pair = make_pair(new_edge, haloi_ele_pt);
12245 
12246  std::pair<std::pair<Node*,Node*>, FiniteElement*>
12247  edge_elementj_pair = make_pair(new_edge_reversed,
12248  haloj_ele_pt);
12249 
12250  // Set default values to later check if values were
12251  // read from the map structure
12252  int face_index_haloi_ele = -1;
12253  face_index_haloi_ele =
12254  edgesi_element_pt_to_face_index[edge_elementi_pair];
12255  int face_index_haloj_ele = -1;
12256  face_index_haloj_ele =
12257  edgesj_element_pt_to_face_index[edge_elementj_pair];
12258  // Verify that there is an element associated with it
12259  if (face_index_haloi_ele == -1 || face_index_haloj_ele == -1)
12260  {
12261  std::stringstream err;
12262  err << "There is no associated face indexes to the"
12263  << "elements that gave\nrise to the shared edge\n"
12264  << "The nodes that compound the edge are these:\n"
12265  << "On processor ("<<iproc<<"):\n"
12266  << "("<<ihalo_edge[0]->x(0)<<", "<<ihalo_edge[0]->x(1)
12267  <<") and ("<<ihalo_edge[1]->x(0)<<", "
12268  <<ihalo_edge[1]->x(1)<<")\n\n"
12269  << "On processor ("<<jproc<<"):\n"
12270  << "("<<jhalo_edge[0]->x(0)<<", "<<jhalo_edge[0]->x(1)
12271  <<") and ("<<jhalo_edge[1]->x(0)<<", "
12272  <<jhalo_edge[1]->x(1)<<")\n\n"
12273  << "The nodes coordinates should be the same!!!\n";
12274  throw OomphLibError(err.str(),
12275  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12276  OOMPH_EXCEPTION_LOCATION);
12277  } // if (face_index_haloi_ele == -1 ||
12278  // face_index_haloj_ele == -1)
12279 
12280  // Get the face indexes from the map structure
12281  Vector<int> tmp_edge_element_face_index;
12282  tmp_edge_element_face_index.push_back(face_index_haloi_ele);
12283  tmp_edge_element_face_index.push_back(face_index_haloj_ele);
12284  // Store the face indexes
12285  edge_element_face[iproc][jproc].
12286  push_back(tmp_edge_element_face_index);
12287 
12288  break; // break for (jhe < nhalo_jedges) since edge found
12289 
12290  } // else if (ihalo_edge[0] == jhalo_edge[1] &&
12291  // ihalo_edge[1] == jhalo_edge[0])
12292 
12293  } // for (jhe < nhaloj_edges)
12294 
12295  } // for (ihe < nhaloi_edges)
12296 
12297  } // if (nhalo_elements_iproc_with_jproc > 0)
12298 
12299  } // for (jproc < nproc)
12300 
12301  } // for (iproc < nproc)
12302 
12303  // ------------------------------------------------------------------
12304  // Compute the degree of each node in the shared edges
12305  // ------------------------------------------------------------------
12306 
12307  // Visit all the shared edges between each pair of processors,
12308  // visit the nodes of each edge and compute the degree of each node
12309 
12310  // Store the degree (valency) of each node
12311  std::map<Node*, unsigned> global_shared_node_degree;
12312 
12313 #ifdef PARANOID
12314  // Map to check if an edge has been already visited
12315  std::map<std::pair<Node*, Node*>,bool> edge_done;
12316 #endif // #ifdef PARANOID
12317  // Map to check if a node has been already visited
12318  std::map<Node*,bool> node_done;
12319 
12320  // Loop over the processors and get the shared edged between each
12321  // pair of processors
12322  for (unsigned iproc = 0; iproc < nproc; iproc++)
12323  {
12324  // Start from iproc + 1 to avoid checking with itself (there is
12325  // no shared edges between the same processor), and to avoid
12326  // double counting the edges and nodes (the shared edges between
12327  // processor (iproc, jproc) are the same as those between
12328  // processor jproc, iproc)
12329  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
12330  {
12331  // Get the number of edges shared between the pair of processors
12332  const unsigned nshd_edges = edges[iproc][jproc].size();
12333 #ifdef PARANOID
12334  // There must be the same number of information on each of the
12335  // containers
12336 
12337  // Get the number of edge elements
12338  const unsigned nedge_element = edge_element_pt[iproc][jproc].size();
12339  if (nshd_edges != nedge_element)
12340  {
12341  std::stringstream error_message;
12342  error_message
12343  << "The number of shared edges between processor iproc and jproc\n"
12344  << "is different form the number of edge elements between the\n"
12345  << "pair of processors\n"
12346  << "iproc: (" << iproc << ")\n"
12347  << "jproc: (" << jproc << ")\n"
12348  << "# of shared edges: (" << nshd_edges << ")\n"
12349  << "# of edge elements: (" << nedge_element << ")\n\n";
12350  throw OomphLibError(error_message.str(),
12351  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12352  OOMPH_EXCEPTION_LOCATION);
12353  }
12354 
12355  // Get the number of edge element faces
12356  const unsigned nedge_element_face =
12357  edge_element_face[iproc][jproc].size();
12358  if (nshd_edges != nedge_element_face)
12359  {
12360  std::stringstream error_message;
12361  error_message
12362  << "The number of shared edges between processor iproc and jproc\n"
12363  << "is different form the number of edge element faces between the\n"
12364  << "pair of processors\n"
12365  << "iproc: (" << iproc << ")\n"
12366  << "jproc: (" << jproc << ")\n"
12367  << "# of shared edges: (" << nshd_edges << ")\n"
12368  << "# of edge element faces: (" << nedge_element_face << ")\n\n";
12369  throw OomphLibError(error_message.str(),
12370  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12371  OOMPH_EXCEPTION_LOCATION);
12372  }
12373 
12374  // Get the number of edge boundaries
12375  const unsigned nedge_boundary = edge_boundary[iproc][jproc].size();
12376  if (nshd_edges != nedge_boundary)
12377  {
12378  std::stringstream error_message;
12379  error_message
12380  << "The number of shared edges between processor iproc and jproc\n"
12381  << "is different form the number of edge boundaries ids between the\n"
12382  << "pair of processors\n"
12383  << "iproc: (" << iproc << ")\n"
12384  << "jproc: (" << jproc << ")\n"
12385  << "# of shared edges: (" << nshd_edges << ")\n"
12386  << "# of edge boundaries ids: (" << nedge_boundary << ")\n\n";
12387  throw OomphLibError(error_message.str(),
12388  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12389  OOMPH_EXCEPTION_LOCATION);
12390  }
12391 
12392 #endif // #ifdef PARANOID
12393 
12394  // Loop over the shared edges between (iproc, jproc) processors
12395  for (unsigned se = 0; se < nshd_edges; se++)
12396  {
12397  // Get the edge
12398  std::pair<Node*, Node*> edge = edges[iproc][jproc][se];
12399 #ifdef PARANOID
12400  // Check that the edge has not been previously visited
12401  if (edge_done[edge])
12402  {
12403  std::stringstream error_message;
12404  error_message
12405  << "The shared edge between processor iproc and processor\n"
12406  << "jproc has been already visited, this is weird since the\n"
12407  << "edge should not be shared by other pair of processors\n"
12408  << "iproc: (" << iproc << ")\n"
12409  << "jproc: (" << jproc << ")\n"
12410  << "First node of edge: (" << edge.first->x(0) << ", "
12411  << edge.first->x(1) << ")\n"
12412  << "Second node of edge: (" << edge.second->x(0) << ", "
12413  << edge.second->x(1) << ")\n"
12414  << "Associated edge boundary id: ("
12415  << edge_boundary[iproc][jproc][se] << ")\n\n";
12416  throw OomphLibError(error_message.str(),
12417  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12418  OOMPH_EXCEPTION_LOCATION);
12419  }
12420 
12421  // Mark the edge as done
12422  edge_done[edge] = true;
12423  // Create the reversed version and include it too
12424  std::pair<Node*, Node*> rev_edge =
12425  std::make_pair(edge.second, edge.first);
12426  // Mark reversed edge as done
12427  edge_done[rev_edge] = true;
12428 #endif // #ifdef PARANOID
12429 
12430  // Get each of the nodes that conform the edge
12431  Node* left_node_pt = edge.first;
12432  Node* right_node_pt = edge.second;
12433 
12434  // Check if the left node has been already done
12435  if (!node_done[left_node_pt])
12436  {
12437  // Set the degree of the node to once since this is the
12438  // first time it has been found
12439  global_shared_node_degree[left_node_pt] = 1;
12440 
12441  } // if (!done_node[left_node_pt])
12442  else
12443  {
12444  // Increase the degree of the node
12445  global_shared_node_degree[left_node_pt]++;
12446  }
12447 
12448  // Check if the right node has been already done
12449  if (!node_done[right_node_pt])
12450  {
12451  // Set the degree of the node to once since this is the
12452  // first time it has been found
12453  global_shared_node_degree[right_node_pt] = 1;
12454  } // if (!done_node[right_node_pt])
12455  else
12456  {
12457  // Increase the degree of the node
12458  global_shared_node_degree[right_node_pt]++;
12459  }
12460 
12461  } // for (se < nshd_edges)
12462 
12463  } // for (jproc < nproc)
12464 
12465  } // for (iproc < nproc)
12466 
12467  // -----------------------------------------------------------------
12468  // Identify those nodes living on edges of original boundaries not
12469  // overlapped by a shared boundary
12470 
12471  // Mark the nodes on original boundaries not overlapped by shared
12472  // boundaries
12473  std::map<unsigned, std::map<Node*, bool> >
12474  node_on_bnd_not_overlapped_by_shd_bnd;
12475 
12476  // Loop over the edges of the original boundaries
12477  for (std::map<std::pair<Node*,Node*>, unsigned>::iterator it_map =
12478  elements_edges_on_boundary.begin();
12479  it_map != elements_edges_on_boundary.end(); it_map++)
12480  {
12481  // Get the edge
12482  std::pair<Node*,Node*> edge_pair = (*it_map).first;
12483 
12484  // Is the edge overlaped by a shared boundary
12485  if (!overlapped_edge[edge_pair])
12486  {
12487  // Mark the nodes of the edge as being on an edge not overlaped
12488  // by a shared boundary on the boundary the edge is
12489  unsigned b = (*it_map).second;
12490 
12491  // Get the left node
12492  Node* left_node_pt = edge_pair.first;
12493  node_on_bnd_not_overlapped_by_shd_bnd[b][left_node_pt] = true;
12494 
12495  // Get the right node
12496  Node* right_node_pt = edge_pair.second;
12497  node_on_bnd_not_overlapped_by_shd_bnd[b][right_node_pt] = true;
12498 
12499  } // if (!overlapped_edge[edge_pair])
12500 
12501  } // Loop over edges to mark those nodes on overlaped edge by
12502  // shared boundaries
12503 
12504  // ------------------------------------------------------------------
12505  // Now create the shared polylines but including the degree of the
12506  // nodes as a nw stop condition for adding more edges to the side
12507  // or a root edge
12508  // ------------------------------------------------------------------
12509 
12510  // Storage for new created polylines with "each processor", non
12511  // sorted (shared polylines of the current processor only)
12512  Vector<Vector<TriangleMeshPolyLine *> > unsorted_polylines_pt(nproc);
12513 
12514  // Map that associates the shared boundary id with the list of
12515  // nodes that create it (shared boundary of the current processor
12516  // only)
12517  std::map<unsigned, std::list<Node*> > shared_bnd_id_to_sorted_list_node_pt;
12518 
12519  // Get maximum user boundary id and set the initial shared boundary
12520  // id
12521  unsigned shared_boundary_id_start = this->nboundary();
12522  Initial_shared_boundary_id = shared_boundary_id_start;
12523 
12524  // Aqui
12525 
12526  // Loop over the processors and get the shared edged between each
12527  // pair of processors
12528  for (unsigned iproc = 0; iproc < nproc; iproc++)
12529  {
12530  // Start from iproc + 1 to avoid checking with itself (there is
12531  // no shared edges between the same processor), and to avoid
12532  // double counting the edges and nodes (the shared edges between
12533  // processor (iproc, jproc) are the same as those between
12534  // processor jproc, iproc)
12535  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
12536  {
12537  // *************************************************************
12538  // THIRD PART
12539  // 1) Sort the edges (make them contiguous) so that they can
12540  // be used as the vertex coordinates that define a shared
12541  // boundary (polyline)
12542  // *************************************************************
12543  unsigned npolylines_counter = 0;
12544  const unsigned nedges = edges[iproc][jproc].size();
12545 
12546  // -----------------------------------------------------------
12547  // Compute all the SHARED POLYLINES
12548  // -----------------------------------------------------------
12549  // The number of sorted edges
12550  unsigned nsorted_edges = 0;
12551 
12552  // Keep track of the already done edges
12553  std::map<std::pair<Node*,Node*>, bool> edge_done;
12554 
12555  // Loop over all the edges to create all the polylines with
12556  // the current processors involved
12557  while(nsorted_edges < nedges)
12558  {
12559  // Temporaly storage for the elements associated to the
12560  // sorted edges
12561  std::list<FiniteElement*> tmp_boundary_element_pt;
12562  // Temporly storage for the face indexes on the element
12563  // that created the given edge
12564  std::list<int> tmp_face_index_element;
12565  // Get an initial pair of nodes to create an edge
12566  std::pair<Node*,Node*> edge;
12567 #ifdef PARANOID
12568  bool found_initial_edge = false;
12569 #endif
12570  int root_edge_bound_id = -1;
12571  unsigned iedge = 0;
12572  for (iedge = 0; iedge < nedges; iedge++)
12573  {
12574  edge = edges[iproc][jproc][iedge];
12575  // If not done then take it as initial edge
12576  if (!edge_done[edge])
12577  {
12578  // Get the boundary id that the edge may be overlapping
12579  root_edge_bound_id = edge_boundary[iproc][jproc][iedge];
12580 #ifdef PARANOID
12581  found_initial_edge = true;
12582 #endif
12583  nsorted_edges++;
12584  iedge++;
12585  break;
12586  } // if (!edge_done[edge])
12587  } // for (iedge < nedges)
12588 
12589 #ifdef PARANOID
12590  if (!found_initial_edge)
12591  {
12592  std::ostringstream error_message;
12593  error_message
12594  << "All the edge are already done, but the number of done\n"
12595  << "edges ("<<nsorted_edges<<") is still less than the total\n"
12596  << "number of edges (" << nedges << ").\n";
12597  // << "----- Possible memory leak -----\n";
12598  throw OomphLibError(error_message.str(),
12599  "TriangleMesh::create_polylines_from_halo_elements_helper()",
12600  OOMPH_EXCEPTION_LOCATION);
12601  }
12602 #endif
12603 
12604  // Storing for the sorting nodes extracted from the
12605  // edges. The sorted nodes are used to create a polyline
12606  std::list<Node*> sorted_nodes;
12607  sorted_nodes.clear();
12608 
12609  // The initial and final nodes of the list
12610  Node *first_node_pt = edge.first;
12611  Node *last_node_pt = edge.second;
12612 
12613  // Push back on the list the new edge (nodes)
12614  sorted_nodes.push_back(first_node_pt);
12615  sorted_nodes.push_back(last_node_pt);
12616 
12617  // Get the elements associated to the edge and store them
12618  // in the temporaly boundary elements storage
12619  tmp_boundary_element_pt.
12620  push_back(edge_element_pt[iproc][jproc][iedge-1][0]);
12621  tmp_boundary_element_pt.
12622  push_back(edge_element_pt[iproc][jproc][iedge-1][1]);
12623 
12624  // ... then get the face index of the element from where
12625  // the edge came from
12626  tmp_face_index_element.
12627  push_back(edge_element_face[iproc][jproc][iedge-1][0]);
12628  tmp_face_index_element.
12629  push_back(edge_element_face[iproc][jproc][iedge-1][1]);
12630 
12631  // Mark edge as done
12632  edge_done[edge] = true;
12633 
12634  // Continue iterating if a new node (that creates a new
12635  // edge) is added to the list, we have just added two nodes
12636  // (the first and last of the root edge)
12637  bool node_added = true;
12638 
12639  // Flags to indicate at which end the node was added (left
12640  // or right)
12641  bool node_added_to_the_left = true;
12642  bool node_added_to_the_right = true;
12643 
12644  // The nodes that create a shared boundary are obtained by
12645  // connecting the edges shared by the halo and haloed
12646  // elements. These edges are connected to left or right of
12647  // the shared boundary. Every time a new edge is added to
12648  // the left (or right), the most left (or right) node is
12649  // searched in the list of nodes of previous shared
12650  // boundaries, if the node is found then it is said to be
12651  // shared with another boundary and a connection to that
12652  // boundary needs to be specified. We stop adding edges
12653  // (and nodes) to the side where that nodes was found to be
12654  // shared. Note that the intersection (shared node) may be
12655  // with the same shared boundary
12656 
12657  // Flag to indicate a node was found to be shared with
12658  // another boundary at the left end (most left node) of the
12659  // shared boundary
12660  bool connection_to_the_left = false;
12661 
12662  // Flag to indicate a node was found to be shared with
12663  // another boundary at the right end (most right node) of
12664  // the shared boundary
12665  bool connection_to_the_right = false;
12666 
12667  // Flag to stop the adding of edges (and nodes) to the
12668  // current shared boundary
12669  bool current_polyline_has_connections_at_both_ends = false;
12670 
12671  // Store the boundary ids of the polylines to connect (only
12672  // used when the polyline was found to have a connection)
12673  // -1: Indicates no connection
12674  // -2: Indicates connection with itself
12675  // Any other value: Boundary id to connect
12676  int bound_id_connection_to_the_left = -1;
12677  int bound_id_connection_to_the_right = -1;
12678 
12679  // Get the degree of the first node
12680  const unsigned first_node_degree =
12681  global_shared_node_degree[first_node_pt];
12682 
12683  // Check if the nodes of the root edge have connections
12684  // ... to the left
12685  bound_id_connection_to_the_left =
12686  check_connections_of_polyline_nodes(
12687  element_in_processor_pt,
12688  root_edge_bound_id,
12689  overlapped_edge,
12690  node_on_bnd_not_overlapped_by_shd_bnd,
12691  sorted_nodes,
12692  shared_bnd_id_to_sorted_list_node_pt,
12693  first_node_degree,
12694  first_node_pt);
12695 
12696  // If there is a connection then set the
12697  // corresponding flag
12698  // (-1): No connection
12699  // (-2): Connection with itself
12700  // (-3): No connection, stop adding nodes
12701  // (other value): Boundary id
12702  if (bound_id_connection_to_the_left != -1)
12703  {
12704  connection_to_the_left = true;
12705  } // if (bound_id_connection_to_the_left != -1)
12706 
12707  // Get the degree of the last node
12708  const unsigned last_node_degree =
12709  global_shared_node_degree[last_node_pt];
12710 
12711  // Check if the nodes of the root edge have connections
12712  // ... to the right
12713  bound_id_connection_to_the_right =
12714  check_connections_of_polyline_nodes(
12715  element_in_processor_pt,
12716  root_edge_bound_id,
12717  overlapped_edge,
12718  node_on_bnd_not_overlapped_by_shd_bnd,
12719  sorted_nodes,
12720  shared_bnd_id_to_sorted_list_node_pt,
12721  last_node_degree,
12722  last_node_pt);
12723 
12724  // If there is a connection then set the
12725  // corresponding flag
12726  // (-1): No connection
12727  // (-2): Connection with itself
12728  // (other value): Boundary id
12729  if (bound_id_connection_to_the_right != -1)
12730  {
12731  connection_to_the_right = true;
12732  } // if (bound_id_connection_to_the_right != -1)
12733 
12734  // If the current shared boundary has connections at both
12735  // ends then stop the adding of nodes
12736  if (connection_to_the_left && connection_to_the_right)
12737  {current_polyline_has_connections_at_both_ends = true;}
12738 
12739  // Continue searching for more edges if
12740  // 1) A new node was added at the left or right of the list
12741  // 2) There are more edges to possible add
12742  // 3) The added node is not part of any other previous
12743  // shared polyline
12744  while(node_added && (nsorted_edges < nedges)
12745  && !current_polyline_has_connections_at_both_ends)
12746  {
12747  // Start from the next edge since we have already added
12748  // the previous one as the initial edge (any previous
12749  // edge had to be added to previous polylines)
12750  for (unsigned iiedge = iedge; iiedge < nedges; iiedge++)
12751  {
12752  // Reset the flags for added nodes, to the left and right
12753  node_added = false;
12754  node_added_to_the_left = false;
12755  node_added_to_the_right = false;
12756  // Get the current edge
12757  edge = edges[iproc][jproc][iiedge];
12758  const int edge_bound_id = edge_boundary[iproc][jproc][iiedge];
12759 
12760  // We need to ensure to connect with edges that share
12761  // the same bound id or with those that has no boundary
12762  // id associated (the default -1 value), may apply
12763  // exclusively to internal boundaries
12764  if (!edge_done[edge] &&
12765  (edge_bound_id == root_edge_bound_id))
12766  {
12767  // Get each individual node
12768  Node* left_node_pt = edge.first;
12769  Node* right_node_pt = edge.second;
12770 
12771  // Pointer to the new added node
12772  Node* new_added_node_pt = 0;
12773 
12774  // Is the node to be added to the left?
12775  if (left_node_pt == first_node_pt &&
12776  !connection_to_the_left)
12777  {
12778  // Push front the new node
12779  sorted_nodes.push_front(right_node_pt);
12780  // Update the new added node and the first node
12781  new_added_node_pt = first_node_pt = right_node_pt;
12782  // Set the node added flag to true
12783  node_added = true;
12784  // Indicate the node was added to the left
12785  node_added_to_the_left = true;
12786  }
12787  // Is the node to be added to the right?
12788  else if (left_node_pt == last_node_pt &&
12789  !connection_to_the_right)
12790  {
12791  // Push back the new node
12792  sorted_nodes.push_back(right_node_pt);
12793  // Update the new added node and the last node
12794  new_added_node_pt = last_node_pt = right_node_pt;
12795  // Set the node added flag to true
12796  node_added = true;
12797  // Indicate the node was added to the right
12798  node_added_to_the_right = true;
12799  }
12800  // Is the node to be added to the left?
12801  else if (right_node_pt == first_node_pt &&
12802  !connection_to_the_left)
12803  {
12804  // Push front the new node
12805  sorted_nodes.push_front(left_node_pt);
12806  // Update the new added node and the first node
12807  new_added_node_pt = first_node_pt = left_node_pt;
12808  // Set the node added flag to true
12809  node_added = true;
12810  // Indicate the node was added to the left
12811  node_added_to_the_left = true;
12812  }
12813  // Is the node to be added to the right?
12814  else if (right_node_pt == last_node_pt &&
12815  !connection_to_the_right)
12816  {
12817  // Push back the new node
12818  sorted_nodes.push_back(left_node_pt);
12819  // Update the new added node and the last node
12820  new_added_node_pt = last_node_pt = left_node_pt;
12821  // Set the node added flag to true
12822  node_added = true;
12823  // Indicate the node was added to the right
12824  node_added_to_the_right = true;
12825  }
12826 
12827  // If we added a new node then we need to check if
12828  // that node has been already added in other shared
12829  // boundaries (which may define a connection)
12830  if (node_added)
12831  {
12832  // Mark as done only if one of its nodes has been
12833  // added to the list
12834  edge_done[edge] = true;
12835  nsorted_edges++;
12836 
12837  // Get the degree of the added node
12838  const unsigned added_node_degree =
12839  global_shared_node_degree[new_added_node_pt];
12840 
12841  if (node_added_to_the_left)
12842  {
12843  // Add the bulk elements
12844  tmp_boundary_element_pt.push_front(
12845  edge_element_pt[iproc][jproc][iiedge][1]);
12846  tmp_boundary_element_pt.push_front(
12847  edge_element_pt[iproc][jproc][iiedge][0]);
12848  // Add the face elements
12849  tmp_face_index_element.push_front(
12850  edge_element_face[iproc][jproc][iiedge][1]);
12851  tmp_face_index_element.push_front(
12852  edge_element_face[iproc][jproc][iiedge][0]);
12853  }
12854 
12855  if (node_added_to_the_right)
12856  {
12857  // Add the bulk elements
12858  tmp_boundary_element_pt.push_back(
12859  edge_element_pt[iproc][jproc][iiedge][0]);
12860  tmp_boundary_element_pt.push_back(
12861  edge_element_pt[iproc][jproc][iiedge][1]);
12862  // Add the face elements
12863  tmp_face_index_element.push_back(
12864  edge_element_face[iproc][jproc][iiedge][0]);
12865  tmp_face_index_element.push_back(
12866  edge_element_face[iproc][jproc][iiedge][1]);
12867  }
12868 
12869  // Based on which side the node was added, look for
12870  // connections on that side
12871 
12872  // Verify for connections to the left (we need to
12873  // check for the connection variable too, since
12874  // after a connection has been done we no longer
12875  // need to verify for this condition)
12876  if (node_added_to_the_left && !connection_to_the_left)
12877  {
12878  // Check for connection
12879  bound_id_connection_to_the_left =
12880  check_connections_of_polyline_nodes(
12881  element_in_processor_pt,
12882  root_edge_bound_id,
12883  overlapped_edge,
12884  node_on_bnd_not_overlapped_by_shd_bnd,
12885  sorted_nodes,
12886  shared_bnd_id_to_sorted_list_node_pt,
12887  added_node_degree,
12888  new_added_node_pt);
12889 
12890  // If there is a connection then set the
12891  // corresponding flag
12892  // (-1): No connection
12893  // (-2): Connection with itself
12894  // (other value): Boundary id
12895  if (bound_id_connection_to_the_left != -1)
12896  {
12897  connection_to_the_left = true;
12898  } // if (bound_id_connection_to_the_left != -1)
12899 
12900  } // if (node_added_to_the_left &&
12901  // !connection_to_the_left)
12902 
12903  // Verify for connections to the right (we need to
12904  // check for the connection variable too, since
12905  // after a connection has been done we no longer
12906  // need to verify for this condition)
12907  if (node_added_to_the_right && !connection_to_the_right)
12908  {
12909  // Check for connection
12910  bound_id_connection_to_the_right =
12911  check_connections_of_polyline_nodes(
12912  element_in_processor_pt,
12913  root_edge_bound_id,
12914  overlapped_edge,
12915  node_on_bnd_not_overlapped_by_shd_bnd,
12916  sorted_nodes,
12917  shared_bnd_id_to_sorted_list_node_pt,
12918  added_node_degree,
12919  new_added_node_pt);
12920 
12921  // If there is a connection then set the
12922  // corresponding flag
12923  // (-1): No connection
12924  // (-2): Connection with itself
12925  // (other value): Boundary id
12926  if (bound_id_connection_to_the_right != -1)
12927  {
12928  connection_to_the_right = true;
12929  } // if (bound_id_connection_to_the_right != -1)
12930 
12931  } // if (node_added_to_the_right &&
12932  // !connection_to_the_right)
12933 
12934  // If the current shared boundary has connections
12935  // at both ends then stop the adding of nodes
12936  if (connection_to_the_left && connection_to_the_right)
12937  {current_polyline_has_connections_at_both_ends = true;}
12938 
12939  // Break the for and re-start to look more edges to
12940  // the left or right
12941  break;
12942 
12943  } // if (node_added)
12944 
12945  } // if (!edge_done[edge])
12946  } // for (iiedge < nedges)
12947 
12948  } // while(node_added && (nsorted_edges < nedges)
12949  // && !current_polyline_has_connections_at_both_ends)
12950 
12951  // ------------------------------------------------------------
12952  // If the sorted nodes of the shared polyline create a loop
12953  // it is necessary to break it by creating as many
12954  // polylines as required
12955 
12956  // Change the list to a vector representation of the
12957  // boundary elements and the face indexes
12958 
12959  // Get the number of boundary elements
12960  const unsigned n_bnd_ele = tmp_boundary_element_pt.size();
12961 
12962  // Storage for the boundary elements and face indexes
12963  Vector<FiniteElement*> tmp_bnd_ele_pt(n_bnd_ele);
12964  Vector<int> tmp_face_idx_ele(n_bnd_ele);
12965  // Helper counter
12966  unsigned help_counter = 0;
12967  // Fill the data structures
12968  for (std::list<FiniteElement*>::iterator it_bnd_ele =
12969  tmp_boundary_element_pt.begin();
12970  it_bnd_ele != tmp_boundary_element_pt.end();
12971  it_bnd_ele++)
12972  {
12973  tmp_bnd_ele_pt[help_counter++] = (*it_bnd_ele);
12974  }
12975 
12976  // Restart counter
12977  help_counter = 0;
12978  for (std::list<int>::iterator it_face_idx =
12979  tmp_face_index_element.begin();
12980  it_face_idx != tmp_face_index_element.end();
12981  it_face_idx++)
12982  {
12983  tmp_face_idx_ele[help_counter++] = (*it_face_idx);
12984  }
12985 
12986  // Store the nodes for the new shared polylines without
12987  // loops
12988  Vector<std::list<Node*> > final_sorted_nodes_pt;
12989  // Store the boundary elements of the shared polyline
12990  // without loops
12991  Vector<Vector<FiniteElement*> > final_boundary_element_pt;
12992  // Face indexes of the boundary elements without loops
12993  Vector<Vector<int> > final_face_index_element;
12994  // Connection flags (to the left) of the shared boundaries
12995  // without loops
12996  Vector<int> final_bound_id_connection_to_the_left;
12997  // Connection flags (to the right) of the shared boundaries
12998  // without loops
12999  Vector<int> final_bound_id_connection_to_the_right;
13000 
13001  // Break any possible loop created by the shared polyline
13002  break_loops_on_shared_polyline_helper(
13003  shared_boundary_id_start,
13004  sorted_nodes,
13005  tmp_bnd_ele_pt, tmp_face_idx_ele,
13006  bound_id_connection_to_the_left, bound_id_connection_to_the_right,
13007  final_sorted_nodes_pt,
13008  final_boundary_element_pt, final_face_index_element,
13009  final_bound_id_connection_to_the_left,
13010  final_bound_id_connection_to_the_right);
13011 
13012  // Get the number of final sorted nodes
13013  const unsigned n_final_sorted_nodes =
13014  final_sorted_nodes_pt.size();
13015 
13016  // Loop over the list of final sorted nodes
13017  for (unsigned i = 0; i < n_final_sorted_nodes; i++)
13018  {
13019  // --------------------------------------------------------
13020  // Associate the list of sorted nodes with the boundary id
13021  // of the shared boundary that is going to be crated
13022  shared_bnd_id_to_sorted_list_node_pt[shared_boundary_id_start] =
13023  final_sorted_nodes_pt[i];
13024 
13025  // Create the shared polyline and fill the data
13026  // structured associated to it
13027  create_shared_polyline(my_rank, shared_boundary_id_start,
13028  iproc, jproc, final_sorted_nodes_pt[i],
13029  root_edge_bound_id,
13030  final_boundary_element_pt[i],
13031  final_face_index_element[i],
13032  unsorted_polylines_pt,
13033  final_bound_id_connection_to_the_left[i],
13034  final_bound_id_connection_to_the_right[i]);
13035 
13036  // Increase the register for the number of created shared
13037  // polylines
13038  npolylines_counter++;
13039 
13040  // Increase the boundary id (the one that will be used by
13041  // the next shared boundary)
13042  shared_boundary_id_start++;
13043 
13044  } // for (i < n_final_sorted_nodes)
13045 
13046  } // while(nsorted_edges < nedges);
13047 
13048  } // for (jproc < nproc)
13049 
13050  // We already have all the shared polylines (shared boundaries)
13051  // of processor iproc with processor jproc. Now we sort them so
13052  // that they be contiguous and can create polygons.
13053 
13054  // If there are polylines to be sorted then sort them
13055  if (unsorted_polylines_pt[iproc].size() > 0)
13056  {
13057  // Now that we have all the new unsorted polylines on "iproc"
13058  // processor it is time to sort them so they be all contiguous
13059  sort_polylines_helper(unsorted_polylines_pt[iproc],
13060  output_polylines_pt[iproc]);
13061  }
13062 
13063 #ifdef PARANOID
13064  const unsigned nunsorted_polylines_iproc =
13065  unsorted_polylines_pt[iproc].size();
13066 
13067  // Verify that all the polylines have been sorted
13068  unsigned tmp_ntotal_polylines = 0;
13069  // Count the total number of sorted polylines
13070  for (unsigned ii = 0 ; ii < output_polylines_pt[iproc].size(); ii++)
13071  {tmp_ntotal_polylines+= output_polylines_pt[iproc][ii].size();}
13072  if (tmp_ntotal_polylines != nunsorted_polylines_iproc)
13073  {
13074  std::ostringstream error_message;
13075  error_message
13076  <<" The total number of unsorted polylines ("
13077  << nunsorted_polylines_iproc << ") in common with\nprocessor ("
13078  << iproc<< ") is different from the total number of sorted "
13079  << "polylines (" << tmp_ntotal_polylines << ") with\nthe same "
13080  << "proessor\n";
13081  throw OomphLibError(error_message.str(),
13082  OOMPH_CURRENT_FUNCTION,
13083  OOMPH_EXCEPTION_LOCATION);
13084  } // if (tmp_ntotal_polylines != nunsorted_polylines_iproc)
13085 #endif
13086 
13087  } // for (iproc < nproc)
13088 
13089  // Establish the last used boundary id
13090  this->Final_shared_boundary_id = shared_boundary_id_start;
13091 
13092  }
13093 
13094  // ======================================================================
13095  // \short Break any possible loop created by the sorted list of nodes
13096  // that is used to create a new shared polyline
13097  // ======================================================================
13098  template<class ELEMENT>
13100  const unsigned &initial_shd_bnd_id,
13101  std::list<Node*> &input_nodes,
13102  Vector<FiniteElement*> &input_boundary_element_pt,
13103  Vector<int> &input_face_index_element,
13104  const int &input_connect_to_the_left,
13105  const int &input_connect_to_the_right,
13106  Vector<std::list<Node*> > &output_sorted_nodes_pt,
13107  Vector<Vector<FiniteElement*> > &output_boundary_element_pt,
13108  Vector<Vector<int> > &output_face_index_element,
13109  Vector<int> &output_connect_to_the_left,
13110  Vector<int> &output_connect_to_the_right)
13111  {
13112  // Get the left and right node of the current list of sorted nodes
13113  Node* left_node_pt = input_nodes.front();
13114  Node* right_node_pt = input_nodes.back();
13115 
13116  // Temporary storage for list of nodes, boundary elements and face
13117  // element's indexes
13118  Vector<std::list<Node*> > tmp_sub_nodes;
13119  Vector<Vector<FiniteElement*> > tmp_sub_bnd_ele_pt;
13120  Vector<Vector<int> > tmp_sub_face_idx_ele;
13121 
13122  // Iterator for the list of input nodes
13123  std::list<Node*>::iterator it = input_nodes.begin();
13124 
13125  // Counter
13126  unsigned counter = 0;
13127 
13128  // Loop while not all nodes have been done
13129  while(it != input_nodes.end())
13130  {
13131  // Check if the current node is the final one
13132  it++;
13133  // Is the current node the final node?
13134  if (it == input_nodes.end())
13135  {
13136  // Break, add no more nodes
13137  break;
13138  }
13139  else
13140  {
13141  // Restore the iterator
13142  it--;
13143  }
13144 
13145  // Get a list of nonrepeated nodes
13146  std::list<Node*> sub_nodes;
13147  // The temporary vector of boundary elements associated with the
13148  // nodes
13149  Vector<FiniteElement*> sub_bnd_ele_pt;
13150  // The temporary vector of face indexes associated with the
13151  // boundary elements
13152  Vector<int> sub_face_idx_ele;
13153 
13154  // Add the current node to the list
13155  sub_nodes.push_back(*it);
13156 
13157  // Add nodes until found a repeated node (the left or right
13158  // node) or until reaching the end of the list of nodes
13159  do
13160  {
13161  // Go to the next node
13162  ++it;
13163 
13164  // Add the new node
13165  sub_nodes.push_back((*it));
13166 
13167  // Add the boundary elements
13168  sub_bnd_ele_pt.push_back(input_boundary_element_pt[counter]);
13169  sub_bnd_ele_pt.push_back(input_boundary_element_pt[counter+1]);
13170 
13171  // Add the face indexes
13172  sub_face_idx_ele.push_back(input_face_index_element[counter]);
13173  sub_face_idx_ele.push_back(input_face_index_element[counter+1]);
13174 
13175  // Increase the counter
13176  counter+=2;
13177 
13178  // Continue adding until reaching a repeated node or the end
13179  // of the list of nodes
13180  }while((*it) != left_node_pt &&
13181  (*it) != right_node_pt &&
13182  it != input_nodes.end());
13183 
13184  // Add the sub-set of nodes to the temporary storage
13185  tmp_sub_nodes.push_back(sub_nodes);
13186  // Add the face elements to the temporary storage
13187  tmp_sub_bnd_ele_pt.push_back(sub_bnd_ele_pt);
13188  // Add the face indexes to the temporary storage
13189  tmp_sub_face_idx_ele.push_back(sub_face_idx_ele);
13190 
13191  } // while((*it) != input_nodes.end())
13192 
13193  // --------------------------------------------------
13194  // Now create as many shared boundaries as required
13195 
13196  // Get the number of sub-list of nodes created
13197  const unsigned n_sub_list = tmp_sub_nodes.size();
13198 
13199 #ifdef PARANOID
13200  if (n_sub_list > 3)
13201  {
13202  std::stringstream error_message;
13203  error_message
13204  << "The number of sub-list of nodes created from the shared\n"
13205  << "polyline with loops was (" << n_sub_list << ").\n"
13206  << "We can only handle up to three sub-list of nodes\n";
13207  throw OomphLibError(error_message.str(),
13208  OOMPH_CURRENT_FUNCTION,
13209  OOMPH_EXCEPTION_LOCATION);
13210  }
13211 #endif
13212 
13213  // If there is only one list it may be because there are no loops or
13214  // there is only one loop (a circle)
13215  if (n_sub_list == 1 && (left_node_pt != right_node_pt))
13216  {
13217  // There are no loops, return just after filling the data
13218  // structures
13219 
13220  // This is the base case used most of the times
13221 
13222  // Set the vector of lists of nodes
13223  output_sorted_nodes_pt = tmp_sub_nodes;
13224  // Set the vector of boundary elements
13225  output_boundary_element_pt = tmp_sub_bnd_ele_pt;
13226  // Set the vector of face indexes
13227  output_face_index_element = tmp_sub_face_idx_ele;
13228 
13229  // Set the connection flags, change them by the proper connection
13230  // flag
13231 
13232 #ifdef PARANOID
13233  if (input_connect_to_the_left == -2)
13234  {
13235  std::stringstream error_message;
13236  error_message
13237  << "The connection flag to the left ("
13238  << input_connect_to_the_left << ") indicates a connection\n"
13239  << "with the same polyline.\n However, only one sub-polyline was "
13240  << "found and no loop\nwas identified\n\n";
13241  throw OomphLibError(error_message.str(),
13242  OOMPH_CURRENT_FUNCTION,
13243  OOMPH_EXCEPTION_LOCATION);
13244  }
13245 #endif
13246 
13247  // The left connection flag
13248  if (input_connect_to_the_left == -3)
13249  {
13250  output_connect_to_the_left.push_back(-1);
13251  }
13252  else
13253  {
13254  output_connect_to_the_left.push_back(input_connect_to_the_left);
13255  }
13256 
13257 #ifdef PARANOID
13258  if (input_connect_to_the_right == -2)
13259  {
13260  std::stringstream error_message;
13261  error_message
13262  << "The connection flag to the right ("
13263  << input_connect_to_the_right << ") indicates a connection\n"
13264  << "with the same polyline.\n However, only one sub-polyline was "
13265  << "found and no loop\nwas identified\n\n";
13266  throw OomphLibError(error_message.str(),
13267  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13268  OOMPH_EXCEPTION_LOCATION);
13269  }
13270 #endif
13271 
13272  // The right connection flag
13273  if (input_connect_to_the_right == -3)
13274  {
13275  output_connect_to_the_right.push_back(-1);
13276  }
13277  else
13278  {
13279  output_connect_to_the_right.push_back(input_connect_to_the_right);
13280  }
13281 
13282  // Return inmediately
13283  return;
13284  }
13285 
13286  // The temporary storage for the shared boundary id
13287  unsigned tmp_shd_bnd_id = initial_shd_bnd_id;
13288 
13289  // -----------------------------------------------------------------
13290  // Check all the sub-list of nodes and create two shared boundaries
13291  // from those that make a loop (circle)
13292 
13293  // -----------------------------------------------------------
13294  // Get the left and right node of the first sub-list of nodes
13295  Node* left_sub_node_pt = tmp_sub_nodes[0].front();
13296  Node* right_sub_node_pt = tmp_sub_nodes[0].back();
13297 
13298  // Check if the sub-list of nodes creates a loop (circle)
13299  if (left_sub_node_pt == right_sub_node_pt)
13300  {
13301  // We need to create two shared polylines and therefore increase
13302  // the shared boundary id by two
13303 
13304  // The first and second half of nodes
13305  std::list<Node*> first_half_node_pt;
13306  std::list<Node*> second_half_node_pt;
13307  // The first and second half of boundary elements
13308  Vector<FiniteElement*> first_half_ele_pt;
13309  Vector<FiniteElement*> second_half_ele_pt;
13310  // The first and second half of face indexes
13311  Vector<int> first_half_face_idx;
13312  Vector<int> second_half_face_idx;
13313 
13314  // Get the number of sub-nodes in the sub-list of nodes
13315  const unsigned n_sub_nodes = tmp_sub_nodes[0].size();
13316 
13317  // The number of sub-nodes for the first half of the shared
13318  // boundary
13319  const unsigned n_sub_nodes_half = static_cast<unsigned>(n_sub_nodes / 2.0);
13320 
13321  // Copy as many sub-nodes for the first half of the sub-polyline
13322 
13323  // Iterator to loop over the nodes
13324  std::list<Node*>::iterator it_sub = tmp_sub_nodes[0].begin();
13325 
13326  // Add the first node
13327  first_half_node_pt.push_back(*it_sub);
13328 
13329  // Skip the first node
13330  it_sub++;
13331 
13332  // Counter
13333  unsigned counter_nodes = 0;
13334  unsigned counter2 = 0;
13335 
13336  // Loop to copy the nodes
13337  for (;it_sub != tmp_sub_nodes[0].end(); it_sub++)
13338  {
13339  // Add the sub-node to the first half
13340  first_half_node_pt.push_back(*it_sub);
13341 
13342  // Add the boundary elements of the first half
13343  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
13344  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2+1]);
13345  // Add the face indexes of the first half
13346  first_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
13347  first_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2+1]);
13348 
13349  // Increase the counter of added nodes
13350  counter_nodes++;
13351 
13352  // Increase the other counter
13353  counter2+=2;
13354 
13355  if (counter_nodes == n_sub_nodes_half)
13356  {
13357  // Stop adding to the first half of nodes
13358  break;
13359  }
13360 
13361  } // Copy the first half of nodes
13362 
13363  // The second half
13364 
13365  // Add the first node of the second half
13366  second_half_node_pt.push_back(*it_sub);
13367 
13368  // Skip the first node of the second half
13369  it_sub++;
13370 
13371  // Loop to copy the nodes
13372  for (;it_sub != tmp_sub_nodes[0].end(); it_sub++)
13373  {
13374  // Add the sub-node to the first half
13375  second_half_node_pt.push_back(*it_sub);
13376 
13377  // Add the boundary elements of the first half
13378  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
13379  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2+1]);
13380  // Add the face indexes of the first half
13381  second_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
13382  second_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2+1]);
13383 
13384  // Increase the other counter
13385  counter2+=2;
13386 
13387  } // Copy the second half of nodes
13388 
13389  // Add the sub-list of nodes to the vector of lists of nodes
13390  output_sorted_nodes_pt.push_back(first_half_node_pt);
13391  output_sorted_nodes_pt.push_back(second_half_node_pt);
13392  // Add the sub-vector of elements to the vector of boundary
13393  // elements
13394  output_boundary_element_pt.push_back(first_half_ele_pt);
13395  output_boundary_element_pt.push_back(second_half_ele_pt);
13396  // Add the sub-vector of face indexes to the vector of face
13397  // indexes
13398  output_face_index_element.push_back(first_half_face_idx);
13399  output_face_index_element.push_back(second_half_face_idx);
13400 
13401  // Set the connection flags, change them by the proper connection
13402  // flag
13403 
13404  // ----------------------------------------------------------------
13405  // Connections flags for the first half
13406 
13407  // The left connection flag
13408 
13409  // Connected with nothing but required to stop adding nodes
13410  if (input_connect_to_the_left == -3)
13411  {
13412  // Set connected to nothing
13413  output_connect_to_the_left.push_back(-1);
13414  }
13415  // Connected with itself
13416  else if (input_connect_to_the_left == -2)
13417  {
13418  // Set connected to nothing, this is the base node
13419  output_connect_to_the_left.push_back(-1);
13420  }
13421  else
13422  {
13423  // Any other value keep it
13424  output_connect_to_the_left.push_back(input_connect_to_the_left);
13425  }
13426 
13427  // The right connection flag
13428 
13429  // Set connected to nothing, this is the base node
13430  output_connect_to_the_right.push_back(-1);
13431 
13432  // Increase the shared boundary id
13433  tmp_shd_bnd_id++;
13434 
13435  // ----------------------------------------------------------------
13436  // Connections flags for the second half
13437 
13438  // The left connection flag
13439 
13440  // Set connected to the previous boundary
13441  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13442 
13443  // The right connection flag
13444 
13445  // Are we in the last sub-list of nodes, if that is the case we
13446  // need to respect the flag assigned to the right
13447  if (n_sub_list == 1)
13448  {
13449  if (input_connect_to_the_right == -3)
13450  {
13451  // Set connected to the previous shared boundary id
13452  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13453  }
13454  else if (input_connect_to_the_right == -2)
13455  {
13456  // Set connected to the previous shared boundary id
13457  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13458  }
13459  else if (input_connect_to_the_right == -1)
13460  {
13461  // Set connected to the previous shared boundary id
13462  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13463  }
13464  else
13465  {
13466  // Any other value keep it
13467  output_connect_to_the_right.push_back(input_connect_to_the_right);
13468  }
13469  } // if (n_sub_list == 1)
13470  else
13471  {
13472  // Set connected to the previous shared boundary id
13473  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13474  }
13475 
13476  // Increase the shared boundary id
13477  tmp_shd_bnd_id++;
13478 
13479  } // if (left_sub_node_pt == right_sub_node_pt)
13480  else
13481  {
13482  // No need to create two boundaries, create only one with the
13483  // sub-list of nodes
13484 
13485  // Add the sub-list of nodes to the vector of lists of nodes
13486  output_sorted_nodes_pt.push_back(tmp_sub_nodes[0]);
13487  // Add the sub-vector of elements to the vector of boundary
13488  // elements
13489  output_boundary_element_pt.push_back(tmp_sub_bnd_ele_pt[0]);
13490  // Add the sub-vector of face indexes to the vector of face
13491  // indexes
13492  output_face_index_element.push_back(tmp_sub_face_idx_ele[0]);
13493 
13494  // Set the connection flags, change them by the proper connection
13495  // flag
13496 
13497  // The left connection flag
13498 
13499  // Connected with nothing but required to stop adding nodes
13500  if (input_connect_to_the_left == -3)
13501  {
13502  // Set to connected to nothing
13503  output_connect_to_the_left.push_back(-1);
13504  }
13505  // Connected with itself
13506  else if (input_connect_to_the_left == -2)
13507  {
13508  // Set connected to the next shared polyline id
13509  output_connect_to_the_left.push_back(tmp_shd_bnd_id+1);
13510  }
13511  else
13512  {
13513  // Any other value keep it
13514  output_connect_to_the_left.push_back(input_connect_to_the_left);
13515  }
13516 
13517  // The right connection flag
13518 
13519  // Set connected to the next shared polyline id
13520  output_connect_to_the_right.push_back(tmp_shd_bnd_id+1);
13521 
13522  // Increase the shared boundary id by one
13523  tmp_shd_bnd_id++;
13524 
13525  } // else if (left_sub_node_pt == right_sub_node_pt)
13526 
13527  // At least two sub-list of nodes were created
13528  if (n_sub_list > 1)
13529  {
13530  // ------------------------------------------------------------
13531  // Get the left and right node of the second sub-list of nodes
13532  left_sub_node_pt = tmp_sub_nodes[1].front();
13533  right_sub_node_pt = tmp_sub_nodes[1].back();
13534 
13535  // Check if the sub-list of nodes creates a loop (circle)
13536  if (left_sub_node_pt == right_sub_node_pt)
13537  {
13538  // We need to create two shared polylines and therefore increase
13539  // the shared boundary id by two
13540 
13541  // The first and second half of nodes
13542  std::list<Node*> first_half_node_pt;
13543  std::list<Node*> second_half_node_pt;
13544  // The first and second half of boundary elements
13545  Vector<FiniteElement*> first_half_ele_pt;
13546  Vector<FiniteElement*> second_half_ele_pt;
13547  // The first and second half of face indexes
13548  Vector<int> first_half_face_idx;
13549  Vector<int> second_half_face_idx;
13550 
13551  // Get the number of sub-nodes in the sub-list of nodes
13552  const unsigned n_sub_nodes = tmp_sub_nodes[1].size();
13553 
13554  // The number of sub-nodes for the first half of the shared
13555  // boundary
13556  const unsigned n_sub_nodes_half = static_cast<unsigned>(n_sub_nodes / 2.0);
13557 
13558  // Copy as many sub-nodes for the first half of the sub-polyline
13559 
13560  // Iterator to loop over the nodes
13561  std::list<Node*>::iterator it_sub = tmp_sub_nodes[1].begin();
13562 
13563  // Add the first node
13564  first_half_node_pt.push_back(*it_sub);
13565 
13566  // Skip the first node
13567  it_sub++;
13568 
13569  // Counter
13570  unsigned counter_nodes = 0;
13571  unsigned counter2 = 0;
13572 
13573  // Loop to copy the nodes
13574  for (;it_sub != tmp_sub_nodes[1].end(); it_sub++)
13575  {
13576  // Add the sub-node to the first half
13577  first_half_node_pt.push_back(*it_sub);
13578  // Add the boundary elements of the first half
13579  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2]);
13580  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2+1]);
13581  // Add the face indexes of the first half
13582  first_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2]);
13583  first_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2+1]);
13584 
13585  // Increase the counter of added nodes
13586  counter_nodes++;
13587 
13588  // Increase the other counter
13589  counter2+=2;
13590 
13591  if (counter_nodes == n_sub_nodes_half)
13592  {
13593  // Stop adding to the first half of nodes
13594  break;
13595  }
13596 
13597  } // Copy the first half of nodes
13598 
13599  // The second half
13600 
13601  // Add the first node of the second half
13602  second_half_node_pt.push_back(*it_sub);
13603 
13604  // Skip the first node of the second half
13605  it_sub++;
13606 
13607  // Loop to copy the nodes
13608  for (;it_sub != tmp_sub_nodes[1].end(); it_sub++)
13609  {
13610  // Add the sub-node to the first half
13611  second_half_node_pt.push_back(*it_sub);
13612  // Add the boundary elements of the first half
13613  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2]);
13614  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[1][counter2+1]);
13615  // Add the face indexes of the first half
13616  second_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2]);
13617  second_half_face_idx.push_back(tmp_sub_face_idx_ele[1][counter2+1]);
13618 
13619  // Increase the other counter
13620  counter2+=2;
13621 
13622  } // Copy the second half of nodes
13623 
13624  // Add the sub-list of nodes to the vector of lists of nodes
13625  output_sorted_nodes_pt.push_back(first_half_node_pt);
13626  output_sorted_nodes_pt.push_back(second_half_node_pt);
13627  // Add the sub-vector of elements to the vector of boundary
13628  // elements
13629  output_boundary_element_pt.push_back(first_half_ele_pt);
13630  output_boundary_element_pt.push_back(second_half_ele_pt);
13631  // Add the sub-vector of face indexes to the vector of face
13632  // indexes
13633  output_face_index_element.push_back(first_half_face_idx);
13634  output_face_index_element.push_back(second_half_face_idx);
13635 
13636  // Set the connection flags, change them by the proper
13637  // connection flag
13638 
13639  // --------------------------------------
13640  // Connections flags for the first half
13641 
13642  // The left connection flag
13643 
13644  // Connected to the previous boundary
13645  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13646 
13647  // The right connection flag
13648 
13649  // Set connected to nothing, this is the base node
13650  output_connect_to_the_right.push_back(-1);
13651 
13652  // Increase the shared boundary id
13653  tmp_shd_bnd_id++;
13654 
13655  // --------------------------------------
13656  // Connections flags for the second half
13657 
13658  // The left connection flag
13659 
13660  // Set connected to the previous boundary
13661  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13662 
13663  // The right connection flag
13664 
13665  // Are we in the last sub-list of nodes, if that is the case we
13666  // need to respect the flag assigned to the right
13667  if (n_sub_list == 2)
13668  {
13669  // Connected with nothing
13670  if (input_connect_to_the_right == -1)
13671  {
13672  // Set connected to the previous shared boundary
13673  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13674  }
13675  // Connected with the same boundary
13676  else if (input_connect_to_the_right == -2)
13677  {
13678  // Set connected to the previous shared boundary
13679  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13680  }
13681  // Connetted with nothing but stop adding nodes
13682  else if (input_connect_to_the_right == -3)
13683  {
13684  // Set connected to the previous shared boundary
13685  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13686  }
13687  else
13688  {
13689  // Any other value keep it
13690  output_connect_to_the_right.push_back(input_connect_to_the_right);
13691  }
13692 
13693  // Increase the shared boundary id
13694  tmp_shd_bnd_id++;
13695 
13696  } // if (n_sub_list == 2)
13697 #ifdef PARANOID
13698  else
13699  {
13700  std::stringstream error_message;
13701  error_message
13702  << "The second sub-list of nodes creates a loop but this is not\n"
13703  << "the last list of sub-nodes.\n"
13704  << "This configuration is not supported\n";
13705  throw OomphLibError(error_message.str(),
13706  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13707  OOMPH_EXCEPTION_LOCATION);
13708  }
13709 #endif
13710 
13711  } // if (left_sub_node_pt == right_sub_node_pt)
13712  else
13713  {
13714  // No need to create two boundaries, create only one with the
13715  // sub-list of nodes
13716 
13717  // Add the sub-list of nodes to the vector of lists of nodes
13718  output_sorted_nodes_pt.push_back(tmp_sub_nodes[1]);
13719  // Add the sub-vector of elements to the vector of boundary
13720  // elements
13721  output_boundary_element_pt.push_back(tmp_sub_bnd_ele_pt[1]);
13722  // Add the sub-vector of face indexes to the vector of face
13723  // indexes
13724  output_face_index_element.push_back(tmp_sub_face_idx_ele[1]);
13725 
13726  // Set the connection flags, change them by the proper connection
13727  // flag
13728 
13729  // The left connection flag
13730 
13731  // Set connected to the previous shared boundary id
13732  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13733 
13734  // The right connection flag
13735 
13736  // Are we in the last sub-list of nodes, if that is the case we
13737  // need to respect the flag assigned to the right
13738  if (n_sub_list == 2)
13739  {
13740  // Connected with nothing but required to stop adding nodes
13741  if (input_connect_to_the_right == -3)
13742  {
13743  // Set to connected to nothing
13744  output_connect_to_the_right.push_back(-1);
13745  }
13746 #ifdef PARANOID
13747  // Connected with itself
13748  else if (input_connect_to_the_right == -2)
13749  {
13750  std::stringstream error_message;
13751  error_message
13752  << "The connection flag to the right ("
13753  << input_connect_to_the_right << ") indicates a connection\n"
13754  << "with the same polyline.\n However, the second sub-list of\n"
13755  << "nodes was found not making a loop so no connection with\n"
13756  << "itself should be marked\n\n";
13757  throw OomphLibError(error_message.str(),
13758  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13759  OOMPH_EXCEPTION_LOCATION);
13760  }
13761 #endif
13762  else
13763  {
13764  // Any other value keep it
13765  output_connect_to_the_right.push_back(input_connect_to_the_right);
13766  }
13767  } // if (n_sub_list == 2)
13768  else
13769  {
13770  // Set connected to the next shared boundary id
13771  output_connect_to_the_right.push_back(tmp_shd_bnd_id+1);
13772  } // else if (n_sub_list == 2)
13773 
13774  // Increase the shared boundary id by one
13775  tmp_shd_bnd_id++;
13776 
13777  } // if (left_sub_node_pt == right_sub_node_pt)
13778 
13779  } // if (n_sub_list > 1)
13780 
13781  // Three sub-list of nodes were created
13782  if (n_sub_list > 2)
13783  {
13784  // ------------------------------------------------------------
13785  // Get the left and right node of the third sub-list of nodes
13786  left_sub_node_pt = tmp_sub_nodes[2].front();
13787  right_sub_node_pt = tmp_sub_nodes[2].back();
13788 
13789  // Check if the sub-list of nodes creates a loop (circle)
13790  if (left_sub_node_pt == right_sub_node_pt)
13791  {
13792  // We need to create two shared polylines and therefore increase
13793  // the shared boundary id by two
13794 
13795  // The first and second half of nodes
13796  std::list<Node*> first_half_node_pt;
13797  std::list<Node*> second_half_node_pt;
13798  // The first and second half of boundary elements
13799  Vector<FiniteElement*> first_half_ele_pt;
13800  Vector<FiniteElement*> second_half_ele_pt;
13801  // The first and second half of face indexes
13802  Vector<int> first_half_face_idx;
13803  Vector<int> second_half_face_idx;
13804 
13805  // Get the number of sub-nodes in the sub-list of nodes
13806  const unsigned n_sub_nodes = tmp_sub_nodes[2].size();
13807 
13808  // The number of sub-nodes for the first half of the shared
13809  // boundary
13810  const unsigned n_sub_nodes_half = static_cast<unsigned>(n_sub_nodes / 2.0);
13811 
13812  // Copy as many sub-nodes for the first half of the sub-polyline
13813 
13814  // Iterator to loop over the nodes
13815  std::list<Node*>::iterator it_sub = tmp_sub_nodes[2].begin();
13816 
13817  // Add the first node
13818  first_half_node_pt.push_back(*it_sub);
13819 
13820  // Skip the first node
13821  it_sub++;
13822 
13823  // Counter
13824  unsigned counter_nodes = 0;
13825  unsigned counter2 = 0;
13826 
13827  // Loop to copy the nodes
13828  for (;it_sub != tmp_sub_nodes[2].end(); it_sub++)
13829  {
13830  // Add the sub-node to the first half
13831  first_half_node_pt.push_back(*it_sub);
13832  // Add the boundary elements of the first half
13833  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2]);
13834  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2+1]);
13835  // Add the face indexes of the first half
13836  first_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2]);
13837  first_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2+1]);
13838 
13839  // Increase the counter of added nodes
13840  counter_nodes++;
13841 
13842  // Increase the other counter
13843  counter2+=2;
13844 
13845  if (counter_nodes == n_sub_nodes_half)
13846  {
13847  // Stop adding to the first half of nodes
13848  break;
13849  }
13850 
13851  } // Copy the first half of nodes
13852 
13853  // The second half
13854 
13855  // Add the first node of the second half
13856  second_half_node_pt.push_back(*it_sub);
13857 
13858  // Skip the first node of the second half
13859  it_sub++;
13860 
13861  // Loop to copy the nodes
13862  for (;it_sub != tmp_sub_nodes[2].end(); it_sub++)
13863  {
13864  // Add the sub-node to the first half
13865  second_half_node_pt.push_back(*it_sub);
13866  // Add the boundary elements of the first half
13867  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2]);
13868  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[2][counter2+1]);
13869  // Add the face indexes of the first half
13870  second_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2]);
13871  second_half_face_idx.push_back(tmp_sub_face_idx_ele[2][counter2+1]);
13872 
13873  // Increase the other counter
13874  counter2+=2;
13875 
13876  } // Copy the second half of nodes
13877 
13878  // Add the sub-list of nodes to the vector of lists of nodes
13879  output_sorted_nodes_pt.push_back(first_half_node_pt);
13880  output_sorted_nodes_pt.push_back(second_half_node_pt);
13881  // Add the sub-vector of elements to the vector of boundary
13882  // elements
13883  output_boundary_element_pt.push_back(first_half_ele_pt);
13884  output_boundary_element_pt.push_back(second_half_ele_pt);
13885  // Add the sub-vector of face indexes to the vector of face
13886  // indexes
13887  output_face_index_element.push_back(first_half_face_idx);
13888  output_face_index_element.push_back(second_half_face_idx);
13889 
13890  // --------------------------------------
13891  // Connections flags for the first half
13892 
13893  // The left connection flag
13894 
13895  // Connected to the previous shared boundary
13896  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13897 
13898  // The right connection flag
13899 
13900  // Set connected to nothing, this is the base node
13901  output_connect_to_the_right.push_back(-1);
13902 
13903  // Increase the shared boundary id
13904  tmp_shd_bnd_id++;
13905 
13906  // --------------------------------------
13907  // Connections flags for the second half
13908 
13909  // The left connection flag
13910 
13911  // Set connected to the previous boundary
13912  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13913 
13914  // The right connection flag
13915 
13916  if (input_connect_to_the_right == -3)
13917  {
13918  // Set connected to the previous shared boundary id
13919  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13920  }
13921  else if (input_connect_to_the_right == -2)
13922  {
13923  // Set connected to the previous shared boundary id
13924  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13925  }
13926  else if (input_connect_to_the_right == -1)
13927  {
13928  // Set connected to the previous shared boundary id
13929  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13930  }
13931  else
13932  {
13933  // Any other value keep it
13934  output_connect_to_the_right.push_back(input_connect_to_the_right);
13935  }
13936 
13937  // Increase the shared boundary id
13938  tmp_shd_bnd_id++;
13939 
13940  } // if (left_sub_node_pt == right_sub_node_pt)
13941  else
13942  {
13943  // No need to create two boundaries, create only one with the
13944  // sub-list of nodes
13945 
13946  // Add the sub-list of nodes to the vector of lists of nodes
13947  output_sorted_nodes_pt.push_back(tmp_sub_nodes[2]);
13948  // Add the sub-vector of elements to the vector of boundary
13949  // elements
13950  output_boundary_element_pt.push_back(tmp_sub_bnd_ele_pt[2]);
13951  // Add the sub-vector of face indexes to the vector of face
13952  // indexes
13953  output_face_index_element.push_back(tmp_sub_face_idx_ele[2]);
13954 
13955  // Set the connection flags, change them by the proper
13956  // connection flag
13957 
13958  // The left connection flag
13959 
13960  // Set connected to the previous shared boundary id
13961  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
13962 
13963  // The right connection flag
13964 
13965  // Connected with nothing but required to stop adding nodes
13966  if (input_connect_to_the_right == -3)
13967  {
13968  std::stringstream error_message;
13969  error_message
13970  << "The connection flag to the right ("
13971  << input_connect_to_the_right << ") indicates 'no connection and\n"
13972  << "stop adding nodes'.\n However, the thrid sub-list of\n"
13973  << "nodes must have a connection to the right with the same\n"
13974  << "shared polyline or with any other polyline\n\n";
13975  throw OomphLibError(error_message.str(),
13976  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13977  OOMPH_EXCEPTION_LOCATION);
13978  }
13979  else if (input_connect_to_the_right == -1)
13980  {
13981  std::stringstream error_message;
13982  error_message
13983  << "The connection flag to the right ("
13984  << input_connect_to_the_right << ") indicates 'no connection.\n"
13985  << "However, the thrid sub-list of nodes must have a connection\n"
13986  << "to the right with the same shared polyline or with any other\n"
13987  << "polyline\n\n";
13988  throw OomphLibError(error_message.str(),
13989  "TriangleMesh::break_loops_on_shared_polyline_helper()",
13990  OOMPH_EXCEPTION_LOCATION);
13991  }
13992  // Connected with itself
13993  else if (input_connect_to_the_right == -2)
13994  {
13995  // Set connected to the previous shared boundary id
13996  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
13997  }
13998  else
13999  {
14000  // Any other value keep it
14001  output_connect_to_the_right.push_back(input_connect_to_the_right);
14002  }
14003 
14004  // Increase the shared boundary id by one
14005  tmp_shd_bnd_id++;
14006 
14007  } // if (left_sub_node_pt == right_sub_node_pt)
14008 
14009  } // if (n_sub_list > 2)
14010 
14011  }
14012 
14013  // ======================================================================
14014  // \short Break any possible loop created by the sorted list of nodes
14015  // that is used to create a new shared polyline
14016  // ======================================================================
14017  template<class ELEMENT>
14020  const unsigned &initial_shd_bnd_id,
14021  std::list<Node*> &input_nodes,
14022  Vector<FiniteElement*> &input_boundary_element_pt,
14023  Vector<FiniteElement*> &input_boundary_face_element_pt,
14024  Vector<int> &input_face_index_element,
14025  const int &input_connect_to_the_left,
14026  const int &input_connect_to_the_right,
14027  Vector<std::list<Node*> > &output_sorted_nodes_pt,
14028  Vector<Vector<FiniteElement*> > &output_boundary_element_pt,
14029  Vector<Vector<FiniteElement*> > &output_boundary_face_element_pt,
14030  Vector<Vector<int> > &output_face_index_element,
14031  Vector<int> &output_connect_to_the_left,
14032  Vector<int> &output_connect_to_the_right)
14033  {
14034  // Get the left and right node of the current list of sorted nodes
14035  Node* left_node_pt = input_nodes.front();
14036  Node* right_node_pt = input_nodes.back();
14037 
14038  // Temporary storage for list of nodes, boundary elements, boundary
14039  // face elements and face element's indexes
14040  Vector<std::list<Node*> > tmp_sub_nodes;
14041  Vector<Vector<FiniteElement*> > tmp_sub_bnd_ele_pt;
14042  Vector<Vector<FiniteElement*> > tmp_sub_bnd_face_ele_pt;
14043  Vector<Vector<int> > tmp_sub_face_idx_ele;
14044 
14045  // Iterator for the list of input nodes
14046  std::list<Node*>::iterator it = input_nodes.begin();
14047 
14048  // Counter
14049  unsigned counter = 0;
14050 
14051  // Loop while not all nodes have been done
14052  while(it != input_nodes.end())
14053  {
14054  // Check if the current node is the final one
14055  it++;
14056  // Is the current node the final node?
14057  if (it == input_nodes.end())
14058  {
14059  // Break, add no more nodes
14060  break;
14061  }
14062  else
14063  {
14064  // Restore the iterator
14065  it--;
14066  }
14067 
14068  // Get a list of nonrepeated nodes
14069  std::list<Node*> sub_nodes;
14070  // The temporary vector of boundary elements associated with the
14071  // nodes
14072  Vector<FiniteElement*> sub_bnd_ele_pt;
14073  // The temporary vector of boundary face elements associated with
14074  // the nodes
14075  Vector<FiniteElement*> sub_bnd_face_ele_pt;
14076  // The temporary vector of face indexes associated with the
14077  // boundary elements
14078  Vector<int> sub_face_idx_ele;
14079 
14080  // Add the current node to the list
14081  sub_nodes.push_back(*it);
14082 
14083  // Add nodes until found a repeated node (the left or right
14084  // node) or until reaching the end of the list of nodes
14085  do
14086  {
14087  // Go to the next node
14088  ++it;
14089 
14090  // Add the new node
14091  sub_nodes.push_back((*it));
14092 
14093  // Add the boundary elements
14094  sub_bnd_ele_pt.push_back(input_boundary_element_pt[counter]);
14095 
14096  // Add the boundary face elements
14097  sub_bnd_face_ele_pt.push_back(input_boundary_face_element_pt[counter]);
14098 
14099  // Add the face indexes
14100  sub_face_idx_ele.push_back(input_face_index_element[counter]);
14101 
14102  // Increase the counter
14103  counter++;
14104 
14105  // Continue adding until reaching a repeated node or the end
14106  // of the list of nodes
14107  }while((*it) != left_node_pt &&
14108  (*it) != right_node_pt &&
14109  it != input_nodes.end());
14110 
14111  // Add the sub-set of nodes to the temporary storage
14112  tmp_sub_nodes.push_back(sub_nodes);
14113 
14114  // Add the boundary elements to the temporary storage
14115  tmp_sub_bnd_ele_pt.push_back(sub_bnd_ele_pt);
14116  // Add the boundary face elements to the temporary storage
14117  tmp_sub_bnd_face_ele_pt.push_back(sub_bnd_face_ele_pt);
14118  // Add the face indexes to the temporary storage
14119  tmp_sub_face_idx_ele.push_back(sub_face_idx_ele);
14120 
14121  } // while((*it) != input_nodes.end())
14122 
14123  // --------------------------------------------------
14124  // Now create as many shared boundaries as required
14125 
14126  // Get the number of sub-list of nodes created
14127  const unsigned n_sub_list = tmp_sub_nodes.size();
14128 
14129 #ifdef PARANOID
14130  if (n_sub_list > 1)
14131  {
14132  std::stringstream error_message;
14133  error_message
14134  << "The number of sub-list of nodes created from the shared\n"
14135  << "polyline with loops was (" << n_sub_list << ").\n"
14136  << "We can only handle one list which may still contain loops\n"
14137  << "(or repeated nodes)\n";
14138  throw OomphLibError(error_message.str(),
14139  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14140  OOMPH_EXCEPTION_LOCATION);
14141  }
14142 #endif
14143 
14144  // If there is only one list it may be because there are no loops or
14145  // there is only one loop (a circle)
14146  if (n_sub_list == 1 && (left_node_pt != right_node_pt))
14147  {
14148  // There are no loops, return just after filling the data
14149  // structures
14150 
14151  // This is the base case used most of the times
14152 
14153  // Set the vector of lists of nodes
14154  output_sorted_nodes_pt = tmp_sub_nodes;
14155  // Set the vector of boundary elements
14156  output_boundary_element_pt = tmp_sub_bnd_ele_pt;
14157  // Set the vector of boundary face elements
14158  output_boundary_face_element_pt = tmp_sub_bnd_face_ele_pt;
14159  // Set the vector of face indexes
14160  output_face_index_element = tmp_sub_face_idx_ele;
14161 
14162  // Set the connection flags, change them by the proper connection
14163  // flag
14164 
14165 #ifdef PARANOID
14166  if (input_connect_to_the_left == -2)
14167  {
14168  std::stringstream error_message;
14169  error_message
14170  << "The connection flag to the left ("
14171  << input_connect_to_the_left << ") indicates a connection\n"
14172  << "with the same polyline.\n However, only one sub-polyline was "
14173  << "found and no loops\nwere identified\n\n";
14174  throw OomphLibError(error_message.str(),
14175  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14176  OOMPH_EXCEPTION_LOCATION);
14177  }
14178 #endif
14179 
14180  // The left connection flag
14181  if (input_connect_to_the_left == -3)
14182  {
14183  output_connect_to_the_left.push_back(-1);
14184  }
14185  else
14186  {
14187  output_connect_to_the_left.push_back(input_connect_to_the_left);
14188  }
14189 
14190 #ifdef PARANOID
14191  if (input_connect_to_the_right == -2)
14192  {
14193  std::stringstream error_message;
14194  error_message
14195  << "The connection flag to the right ("
14196  << input_connect_to_the_right << ") indicates a connection\n"
14197  << "with the same polyline.\n However, only one sub-polyline was "
14198  << "found and no loops\nwere identified\n\n";
14199  throw OomphLibError(error_message.str(),
14200  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14201  OOMPH_EXCEPTION_LOCATION);
14202  }
14203 #endif
14204 
14205  // The right connection flag
14206  if (input_connect_to_the_right == -3)
14207  {
14208  output_connect_to_the_right.push_back(-1);
14209  }
14210  else
14211  {
14212  output_connect_to_the_right.push_back(input_connect_to_the_right);
14213  }
14214 
14215  // Return immediately
14216  return;
14217  }
14218 
14219  // The temporary storage for the shared boundary id
14220  unsigned tmp_shd_bnd_id = initial_shd_bnd_id;
14221 
14222  // -----------------------------------------------------------------
14223  // Check all the sub-list of nodes and create two shared boundaries
14224  // from those that make a loop (circle)
14225 
14226  // -----------------------------------------------------------
14227  // Get the left and right node of the first sub-list of nodes
14228  Node* left_sub_node_pt = tmp_sub_nodes[0].front();
14229  Node* right_sub_node_pt = tmp_sub_nodes[0].back();
14230 
14231  // Check if the sub-list of nodes creates a loop (circle)
14232  if (left_sub_node_pt == right_sub_node_pt)
14233  {
14234  // We need to create two shared polylines and therefore increase
14235  // the shared boundary id by two
14236 
14237  // The first and second half of nodes
14238  std::list<Node*> first_half_node_pt;
14239  std::list<Node*> second_half_node_pt;
14240  // The first and second half of boundary elements
14241  Vector<FiniteElement*> first_half_ele_pt;
14242  Vector<FiniteElement*> second_half_ele_pt;
14243  // The first and second half of boundary face elements
14244  Vector<FiniteElement*> first_half_ele_face_pt;
14245  Vector<FiniteElement*> second_half_ele_face_pt;
14246  // The first and second half of face indexes
14247  Vector<int> first_half_face_idx;
14248  Vector<int> second_half_face_idx;
14249 
14250  // Get the number of sub-nodes in the sub-list of nodes
14251  const unsigned n_sub_nodes = tmp_sub_nodes[0].size();
14252 
14253  // The number of sub-nodes for the first half of the shared
14254  // boundary
14255  const unsigned n_sub_nodes_half = static_cast<unsigned>(n_sub_nodes / 2.0);
14256 
14257  // Copy as many sub-nodes for the first half of the sub-polyline
14258 
14259  // Iterator to loop over the nodes
14260  std::list<Node*>::iterator it_sub = tmp_sub_nodes[0].begin();
14261 
14262  // Add the first node
14263  first_half_node_pt.push_back(*it_sub);
14264 
14265  // Skip the first node
14266  it_sub++;
14267 
14268  // Counter
14269  unsigned counter_nodes = 0;
14270  unsigned counter2 = 0;
14271 
14272  // Loop to copy the nodes
14273  for (;it_sub != tmp_sub_nodes[0].end(); it_sub++)
14274  {
14275  // Add the sub-node to the first half
14276  first_half_node_pt.push_back(*it_sub);
14277 
14278  // Add the boundary elements of the first half
14279  first_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
14280  // Add the boundary face elements of the first half
14281  first_half_ele_face_pt.push_back(tmp_sub_bnd_face_ele_pt[0][counter2]);
14282  // Add the face indexes of the first half
14283  first_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
14284 
14285  // Increase the counter of added nodes
14286  counter_nodes++;
14287 
14288  // Increase the other counter (of the elements/face)
14289  counter2++;
14290 
14291  if (counter_nodes == n_sub_nodes_half)
14292  {
14293  // Stop adding to the first half of nodes
14294  break;
14295  }
14296 
14297  } // Copy the first half of nodes
14298 
14299  // The second half
14300 
14301  // Add the first node of the second half
14302  second_half_node_pt.push_back(*it_sub);
14303 
14304  // Skip the first node of the second half
14305  it_sub++;
14306 
14307  // Loop to copy the nodes
14308  for (;it_sub != tmp_sub_nodes[0].end(); it_sub++)
14309  {
14310  // Add the sub-node to the first half
14311  second_half_node_pt.push_back(*it_sub);
14312 
14313  // Add the boundary elements of the first half
14314  second_half_ele_pt.push_back(tmp_sub_bnd_ele_pt[0][counter2]);
14315  // Add the boundary face elements of the first half
14316  second_half_ele_face_pt.push_back(tmp_sub_bnd_face_ele_pt[0][counter2]);
14317  // Add the face indexes of the first half
14318  second_half_face_idx.push_back(tmp_sub_face_idx_ele[0][counter2]);
14319 
14320  // Increase the other counter
14321  counter2++;
14322 
14323  } // Copy the second half of nodes
14324 
14325  // Add the sub-list of nodes to the vector of lists of nodes
14326  output_sorted_nodes_pt.push_back(first_half_node_pt);
14327  output_sorted_nodes_pt.push_back(second_half_node_pt);
14328  // Add the sub-vector of elements to the vector of boundary
14329  // elements
14330  output_boundary_element_pt.push_back(first_half_ele_pt);
14331  output_boundary_element_pt.push_back(second_half_ele_pt);
14332  // Add the sub-vector of face elements to the vector of boundary
14333  // elements
14334  output_boundary_face_element_pt.push_back(first_half_ele_face_pt);
14335  output_boundary_face_element_pt.push_back(second_half_ele_face_pt);
14336  // Add the sub-vector of face indexes to the vector of face
14337  // indexes
14338  output_face_index_element.push_back(first_half_face_idx);
14339  output_face_index_element.push_back(second_half_face_idx);
14340 
14341  // Set the connection flags, change them by the proper connection
14342  // flag
14343 
14344  // ----------------------------------------------------------------
14345  // Connections flags for the first half
14346 
14347  // The left connection flag
14348 
14349  // Connected with nothing but required to stop adding nodes
14350  if (input_connect_to_the_left == -3)
14351  {
14352  // Set connected to nothing
14353  output_connect_to_the_left.push_back(-1);
14354  }
14355  // Connected with itself
14356  else if (input_connect_to_the_left == -2)
14357  {
14358  // Set connected to nothing, this is the base node
14359  output_connect_to_the_left.push_back(-1);
14360  }
14361  else
14362  {
14363  // Any other value keep it
14364  output_connect_to_the_left.push_back(input_connect_to_the_left);
14365  }
14366 
14367  // The right connection flag
14368 
14369  // Set connected to nothing, this is the base node
14370  output_connect_to_the_right.push_back(-1);
14371 
14372  // Increase the shared boundary id
14373  tmp_shd_bnd_id++;
14374 
14375  // ----------------------------------------------------------------
14376  // Connections flags for the second half
14377 
14378  // The left connection flag
14379 
14380  // Set connected to the previous boundary
14381  output_connect_to_the_left.push_back(tmp_shd_bnd_id-1);
14382 
14383  // The right connection flag
14384 
14385  // Are we in the last sub-list of nodes, if that is the case we
14386  // need to respect the flag assigned to the right
14387  if (n_sub_list == 1)
14388  {
14389  if (input_connect_to_the_right == -3)
14390  {
14391  // Set connected to the previous shared boundary id
14392  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
14393  }
14394  else if (input_connect_to_the_right == -2)
14395  {
14396  // Set connected to the previous shared boundary id
14397  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
14398  }
14399  else if (input_connect_to_the_right == -1)
14400  {
14401  // Set connected to the previous shared boundary id
14402  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
14403  }
14404  else
14405  {
14406  // Any other value keep it
14407  output_connect_to_the_right.push_back(input_connect_to_the_right);
14408  }
14409  } // if (n_sub_list == 1)
14410  else
14411  {
14412  // Set connected to the previous shared boundary id
14413  output_connect_to_the_right.push_back(tmp_shd_bnd_id-1);
14414  }
14415 
14416  // Increase the shared boundary id
14417  tmp_shd_bnd_id++;
14418 
14419  } // if (left_sub_node_pt == right_sub_node_pt)
14420 #ifdef PARANOID
14421  else
14422  {
14423  std::stringstream error_message;
14424  error_message
14425  << "The initial and final node in the current shared polyline are not\n"
14426  << "the same and the number of sublists is ("<< n_sub_list << ").\n"
14427  << "We can not handle more than one sublist in the method to break\n"
14428  << "loops at the load balance stage\n\n";
14429  throw OomphLibError(error_message.str(),
14430  "TriangleMesh::break_loops_on_shared_polyline_load_balance_helper()",
14431  OOMPH_EXCEPTION_LOCATION);
14432  }
14433 #endif
14434 
14435  }
14436 
14437  // ======================================================================
14438  // \short Create the shared polyline and fill the data structured
14439  // that keep all the information associated with the creationg of the
14440  // shared boundary
14441  // ======================================================================
14442  template<class ELEMENT>
14444  create_shared_polyline(const unsigned &my_rank,
14445  const unsigned &shd_bnd_id,
14446  const unsigned &iproc,
14447  const unsigned &jproc,
14448  std::list<Node*> &sorted_nodes,
14449  const int &root_edge_bnd_id,
14450  Vector<FiniteElement*> &bulk_bnd_ele_pt,
14451  Vector<int> &face_index_ele,
14452  Vector<Vector<TriangleMeshPolyLine *> >
14453  &unsorted_polylines_pt,
14454  const int &connect_to_the_left_flag,
14455  const int &connect_to_the_right_flag)
14456  {
14457  // ----------------------------------------------------------------
14458  // Associate the shared boundary with the respective processors
14459  // ----------------------------------------------------------------
14460 
14461  // Setup the global look-up scheme, where all processors know the
14462  // associations of others processors and the shared boundaries they
14463  // created
14464 
14465  // Set up the boundary shared by "iproc" with "jproc" processor
14466  Shared_boundaries_ids[iproc][jproc].push_back(shd_bnd_id);
14467 
14468  // Set up the boundary shared by "jproc" with "iproc" processor
14469  Shared_boundaries_ids[jproc][iproc].push_back(shd_bnd_id);
14470 
14471  // Specify the processors involved on the creation of the shared
14472  // boundary
14473  Vector<unsigned> processors(2);
14474  processors[0] = iproc;
14475  processors[1] = jproc;
14476  Shared_boundary_from_processors[shd_bnd_id] = processors;
14477 
14478  // ----------------------------------------------------------------
14479  // If one of the processor associated with the shared boundary is
14480  // the current processor then it needs to create a polyline from the
14481  // input sorted nodes, other processors can skip this part
14482  if (iproc == my_rank || jproc == my_rank)
14483  {
14484  // ------------------------------------------------------------
14485  // Create a vertices representation from the sorted nodes list
14486  // ------------------------------------------------------------
14487 
14488  // Get the number of nodes on the list
14489  const unsigned n_nodes = sorted_nodes.size();
14490  // The vector to store the vertices (assign space)
14491  Vector<Vector<double> > vertices(n_nodes);
14492 
14493  // Copy the vertices from the nodes
14494  unsigned counter = 0;
14495 
14496  for (std::list<Node*>::iterator it = sorted_nodes.begin();
14497  it != sorted_nodes.end(); it++)
14498  {
14499  vertices[counter].resize(2);
14500  vertices[counter][0] = (*it)->x(0);
14501  vertices[counter][1] = (*it)->x(1);
14502  counter++;
14503  }
14504 
14505  // ---------------------------------------------
14506  // Create the polyline from the input vertices
14507  // ---------------------------------------------
14508  TriangleMeshPolyLine *polyline_pt =
14509  new TriangleMeshPolyLine(vertices, shd_bnd_id);
14510 
14511  // ---------------------------------------------
14512  // Establish the internal boundary information
14513  // ---------------------------------------------
14514 
14515  // Check if the shared boundary is overlapping (or is part) of an
14516  // internal boundary
14517  if (root_edge_bnd_id != -1)
14518  {
14519  // If the shared boundary is part of an internal boundary then
14520  // mark the shared boundary
14521  Shared_boundary_overlaps_internal_boundary[shd_bnd_id] =
14522  static_cast<unsigned>(root_edge_bnd_id);
14523  } // if (root_edge_bnd_id != -1)
14524 
14525  // ---------------------------------------------
14526  // Store the boundary elements and face indexes
14527  // ---------------------------------------------
14528 
14529  // Store the shared boundary elements
14530  const unsigned n_shared_boundary_elements = bulk_bnd_ele_pt.size();
14531 #ifdef PARANOID
14532  // Check that the number of shared boundy elements is the same as
14533  // the number of face indexes
14534  const unsigned n_face_index = face_index_ele.size();
14535  if (n_shared_boundary_elements != n_face_index)
14536  {
14537  std::ostringstream error_message;
14538  error_message
14539  << "The number of shared boundary elements is different from the\n"
14540  << "number of face indexes associated to the shared boundary\n"
14541  << "elements\n"
14542  << "Number of shared boundary elements: ("
14543  << n_shared_boundary_elements << ")\n"
14544  << "Number of face indexes: (" << n_face_index << ")\n\n";
14545  throw OomphLibError(error_message.str(),
14546  "TriangleMesh::create_shared_polyline()",
14547  OOMPH_EXCEPTION_LOCATION);
14548  } // if (n_shared_boundary_elements != n_face_index)
14549 #endif
14550 
14551  // Add the shared boundary elements and their respective face
14552  // indexes to their permanent containers
14553  for (unsigned i = 0 ; i < n_shared_boundary_elements; i++)
14554  {
14555  add_shared_boundary_element(shd_bnd_id, bulk_bnd_ele_pt[i]);
14556  add_face_index_at_shared_boundary(shd_bnd_id, face_index_ele[i]);
14557  } // for (i < nshared_boundary_elements)
14558 
14559  // Store the shared boundary nodes
14560  for (std::list<Node*>::iterator it = sorted_nodes.begin();
14561  it != sorted_nodes.end(); it++)
14562  {
14563  add_shared_boundary_node(shd_bnd_id, (*it));
14564  } // for (it != sorted_nodes.end())
14565 
14566  // ----------------------------------------------------------
14567  // Create additional look-up schemes for the shared boundary
14568  // ----------------------------------------------------------
14569 
14570  // Updates bnd_id <---> curve section map
14571  this->Boundary_curve_section_pt[shd_bnd_id] = polyline_pt;
14572 
14573  // Check the size of the unsorted_polylines_pt structure. This
14574  // will have n_procs = 1 when it was called from the
14575  // create_new_shared_boundaries() methods
14576  const unsigned n_procs = unsorted_polylines_pt.size();
14577  if (n_procs > 1)
14578  {
14579  // Add the new created polyline to the list of unsorted
14580  // polylines
14581  unsorted_polylines_pt[iproc].push_back(polyline_pt);
14582 
14583  // ... do this on both processors involved in the creation of
14584  // the shared boundary
14585  unsorted_polylines_pt[jproc].push_back(polyline_pt);
14586  }
14587  else
14588  {
14589  // Add the new created polyline to the list of unsorted
14590  // polylines
14591  unsorted_polylines_pt[0].push_back(polyline_pt);
14592  }
14593 
14594  // Mark the polyline for deletion (when calling destructor)
14595  this->Free_curve_section_pt.insert(polyline_pt);
14596 
14597  // ----------------------------
14598  // Set connection information
14599  // ----------------------------
14600 
14601  // Check that the flags are correct, no connection or the boundary
14602  // id of the boundary to connect
14603 #ifdef PARANOID
14604  // Is the shared polyline not connected to the left
14605  if (connect_to_the_left_flag < 0)
14606  {
14607  // If not connected then should be specified by -1
14608  if (connect_to_the_left_flag != -1)
14609  {
14610  std::ostringstream error_message;
14611  error_message
14612  << "The only accepted values for the connection flags are:\n"
14613  << "POSITIVE values or -1, any other value is rejected, please\n"
14614  << "check that you previously called the methods to deal with\n"
14615  << "other flag values\n"
14616  << "The current flag value for connection to the left is: ("
14617  << connect_to_the_left_flag<<")\n\n";
14618  throw OomphLibError(error_message.str(),
14619  "TriangleMesh::create_shared_polyline()",
14620  OOMPH_EXCEPTION_LOCATION);
14621  } // if (connect_to_the_left_flag != -1)
14622  } // if (connect_to_the_left_flag < 0)
14623 
14624  // Is the shared polyline not connected to the right
14625  if (connect_to_the_right_flag < 0)
14626  {
14627  // If not connected then should be specified by -1
14628  if (connect_to_the_right_flag != -1)
14629  {
14630  std::ostringstream error_message;
14631  error_message
14632  << "The only accepted values for the connection flags are:\n"
14633  << "POSITIVE values or -1, any other value is rejected, please\n"
14634  << "check that you previously called the methods to deal with\n"
14635  << "other flag values\n"
14636  << "The current flag value for connection to the right is: ("
14637  << connect_to_the_right_flag<<")\n\n";
14638  throw OomphLibError(error_message.str(),
14639  "TriangleMesh::create_shared_polyline()",
14640  OOMPH_EXCEPTION_LOCATION);
14641  } // if (connect_to_the_right_flag != -1)
14642  } // if (connect_to_the_right_flag < 0)
14643 #endif
14644 
14645  // Set the connection to the left
14646  if (connect_to_the_left_flag != -1)
14647  {
14648  // Get the unsigned version of the boundary id to the left
14649  const unsigned bnd_id_connection_to_the_left =
14650  static_cast<unsigned>(connect_to_the_left_flag);
14651  // Set the initial vertex as connected
14652  polyline_pt->set_initial_vertex_connected();
14653  // Set the initial vertex connected boundary id
14654  polyline_pt->initial_vertex_connected_bnd_id() =
14655  bnd_id_connection_to_the_left;
14656  // Set the chunk number to zero
14657  polyline_pt->initial_vertex_connected_n_chunk() = 0;
14658 
14659  } // if (connect_to_the_left_flag != -1)
14660 
14661  // Set the connection to the right
14662  if (connect_to_the_right_flag != -1)
14663  {
14664  // Get the unsigned version of the boundary id to the right
14665  const unsigned bnd_id_connection_to_the_right =
14666  static_cast<unsigned>(connect_to_the_right_flag);
14667  // Set the final vertex as connected
14668  polyline_pt->set_final_vertex_connected();
14669  // Set the final vertex connected boundary id
14670  polyline_pt->final_vertex_connected_bnd_id() =
14671  bnd_id_connection_to_the_right;
14672  // Set the chunk number to zero
14673  polyline_pt->final_vertex_connected_n_chunk() = 0;
14674 
14675  } // if (connect_to_the_right_flag != -1)
14676 
14677  } // if (iproc == my_rank || jproc == my_rank)
14678 
14679  }
14680 
14681  //======================================================================
14682  /// \short Reset the boundary elements info. after load balance have
14683  /// taken place
14684  //======================================================================
14685  template <class ELEMENT>
14687  reset_boundary_element_info(Vector<unsigned> &ntmp_boundary_elements,
14688  Vector<Vector<unsigned> >
14689  &ntmp_boundary_elements_in_region,
14690  Vector<FiniteElement*> &deleted_elements)
14691  {
14692  // Get the number of boundaries
14693  const unsigned nbound = this->nboundary();
14694 
14695  // Are there regions?
14696  const unsigned n_regions = this->nregion();
14697 
14698  // Loop over the boundaries
14699  for (unsigned b = 0; b < nbound; b++)
14700  {
14701  // Get the boundary elements and back them up
14702  // -----------------------------------------------------------------
14703  // Get the number of boundary elements (mixed with the old and new)
14704  const unsigned nbound_ele = this->nboundary_element(b);
14705  // Back-up the boundary elements
14706  Vector<FiniteElement*> backed_up_boundary_element_pt(nbound_ele);
14707  Vector<int> backed_up_face_index_at_boundary(nbound_ele);
14708  for (unsigned e = 0; e < nbound_ele; e++)
14709  {
14710  // Get the old boundary element
14711  backed_up_boundary_element_pt[e] = this->boundary_element_pt(b, e);
14712  // Get the old face index
14713  backed_up_face_index_at_boundary[e] =
14714  this->face_index_at_boundary(b, e);
14715  } // for (n < nold_boundary_elements)
14716 
14717  // Back up the elements in boundary for each region
14718  Vector<Vector<FiniteElement*> >
14719  backed_up_boundary_region_element_pt(n_regions);
14720  Vector<Vector<int> > backed_up_face_index_at_boundary_region(n_regions);
14721 
14722  // Loop over the regions and back up the boundary elements in
14723  // regions
14724  for (unsigned ir = 0; ir < n_regions; ir++)
14725  {
14726  // Get the region id
14727  const unsigned region_id =
14728  static_cast<unsigned>(this->region_attribute(ir));
14729  // Get the number of boundary region elements (mixed old and new)
14730  const unsigned nbnd_region_ele =
14731  this->nboundary_element_in_region(b, region_id);
14732 
14733  // Loop over the elements in the region
14734  for (unsigned e = 0; e < nbnd_region_ele; e++)
14735  {
14736  // Get the old boundary region element
14737  backed_up_boundary_region_element_pt[ir][e] =
14738  this->boundary_element_in_region_pt(b, region_id, e);
14739 
14740  // Get the old face index
14741  backed_up_face_index_at_boundary_region[ir][e] =
14742  this->face_index_at_boundary_in_region(b, region_id, e);
14743  } // for (e < nbnd_region_ele)
14744 
14745  } // for (ir < n_regions)
14746 
14747  // Clean all previous storages
14748  this->Boundary_element_pt[b].clear();
14749  this->Face_index_at_boundary[b].clear();
14750  if (n_regions > 0)
14751  {
14752  this->Boundary_region_element_pt[b].clear();
14753  this->Face_index_region_at_boundary[b].clear();
14754  }
14755 
14756  // -------------------------------------------------------------------
14757  // Now copy only the elements that are still alive, from those before
14758  // the re-establishment of halo and haloed elements
14759  // -------------------------------------------------------------------
14760  // Start with the boundary elements
14761  // Get the old number of boundary elements
14762  const unsigned nold_bnd_ele = ntmp_boundary_elements[b];
14763  // Loop over the boundary elements and check those still alive
14764  for (unsigned e = 0; e < nold_bnd_ele; e++)
14765  {
14766  FiniteElement* tmp_ele_pt = backed_up_boundary_element_pt[e];
14767  // Include only those elements still alive
14768  Vector<FiniteElement*>::iterator it =
14769  std::find(deleted_elements.begin(),
14770  deleted_elements.end(),
14771  tmp_ele_pt);
14772  // Only copy thoes elements not found on the deleted elements
14773  // container
14774  if (it == deleted_elements.end())
14775  {
14776  FiniteElement* add_ele_pt = backed_up_boundary_element_pt[e];
14777  this->Boundary_element_pt[b].push_back(add_ele_pt);
14778  const int face_index = backed_up_face_index_at_boundary[e];
14779  this->Face_index_at_boundary[b].push_back(face_index);
14780  } // if (tmp_ele_pt != 0)
14781 
14782  } // for (n < nold_bnd_ele)
14783 
14784  // ... continue with the boundary elements in specific regions
14785 
14786  // Loop over the regions
14787  for (unsigned ir = 0; ir < n_regions; ir++)
14788  {
14789  // Get the region id
14790  const unsigned region_id =
14791  static_cast<unsigned>(this->region_attribute(ir));
14792 
14793  // Get the old number of boundary elements in region
14794  const unsigned nold_bnd_region_ele =
14795  ntmp_boundary_elements_in_region[b][ir];
14796 
14797  // Loop over the boundary region elements and check those still
14798  // alive
14799  for (unsigned e = 0; e < nold_bnd_region_ele; e++)
14800  {
14801  // Get the element
14802  FiniteElement* tmp_ele_pt =
14803  backed_up_boundary_region_element_pt[ir][e];
14804  // Include only those elements still alive
14805  Vector<FiniteElement*>::iterator it =
14806  std::find(deleted_elements.begin(),
14807  deleted_elements.end(),
14808  tmp_ele_pt);
14809  // Only copy those elements not found on the deleted elements
14810  // container
14811  if (it == deleted_elements.end())
14812  {
14813  FiniteElement* add_ele_pt =
14814  backed_up_boundary_region_element_pt[ir][e];
14815  this->Boundary_region_element_pt[b][region_id].push_back(add_ele_pt);
14816  const int face_index = backed_up_face_index_at_boundary_region[ir][e];
14817  this->Face_index_region_at_boundary[b][region_id].
14818  push_back(face_index);
14819  } // if (tmp_ele_pt != 0)
14820 
14821  } // for (n < nbound_ele)
14822 
14823  } // for (ir < n_regions)
14824 
14825  // ----------------------------------------------------------------
14826  // Now copy all those elements created after the re-establishment
14827  // of halo and haloed elements
14828  // ----------------------------------------------------------------
14829  // Loop over the boundary elements
14830  for (unsigned e = nold_bnd_ele; e < nbound_ele; e++)
14831  {
14832  FiniteElement* add_ele_pt = backed_up_boundary_element_pt[e];
14833  this->Boundary_element_pt[b].push_back(add_ele_pt);
14834  const int face_index = backed_up_face_index_at_boundary[e];
14835  this->Face_index_at_boundary[b].push_back(face_index);
14836  } // for (e < nbound_ele)
14837 
14838  // Now add the boundary elements in regions
14839 
14840  // Loop over the regions
14841  for (unsigned ir = 0; ir < n_regions; ir++)
14842  {
14843  // Get the region id
14844  const unsigned region_id =
14845  static_cast<unsigned>(this->region_attribute(ir));
14846 
14847  // Get the old number of boundary elements in region
14848  const unsigned nold_bnd_region_ele =
14849  ntmp_boundary_elements_in_region[b][ir];
14850 
14851  // Get the new number of boundary elements in region
14852  const unsigned nbnd_region_ele =
14853  this->nboundary_element_in_region(b, region_id);
14854 
14855  // Loop over the boundary region elements and check those still
14856  // alive
14857  for (unsigned e = nold_bnd_region_ele; e < nbnd_region_ele; e++)
14858  {
14859  FiniteElement* add_ele_pt = backed_up_boundary_region_element_pt[ir][e];
14860  this->Boundary_region_element_pt[b][region_id].push_back(add_ele_pt);
14861  const int face_index = backed_up_face_index_at_boundary_region[ir][e];
14862  this->Face_index_region_at_boundary[b][region_id].push_back(face_index);
14863  } // for (e < nbnd_region_ele)
14864 
14865  } // for (ir < n_regions)
14866 
14867  } // for (b < nbound)
14868 
14869  // Lookup scheme has now been setup yet
14870  Lookup_for_elements_next_boundary_is_setup=true;
14871 
14872  }
14873 
14874 #endif // OOMPH_HAS_MPI
14875 
14876 #ifdef OOMPH_HAS_TRIANGLE_LIB
14877 
14878 //========================================================================
14879 /// Build a new TriangulateIO object based on target areas specified
14880 //========================================================================
14881 template <class ELEMENT>
14883  TriangulateIO& triangulate_io,
14884  const Vector<double>& target_area,
14885  struct TriangulateIO& triangle_refine)
14886  {
14887 
14888  // Initialize
14889  TriangleHelper::initialise_triangulateio(triangle_refine);
14890 
14891  // Store the global number of vertices and segments
14892  // in the list
14893  unsigned n_points = triangulate_io.numberofpoints;
14894  triangle_refine.numberofpoints=n_points;
14895 
14896  unsigned n_segments=triangulate_io.numberofsegments;
14897  triangle_refine.numberofsegments=n_segments;
14898 
14899  // Initialization of the TriangulateIO objects to store the values
14900  triangle_refine.pointlist =
14901  (double *) malloc(triangulate_io.numberofpoints * 2 * sizeof(double));
14902  triangle_refine.pointmarkerlist =
14903  (int *) malloc(triangulate_io.numberofpoints * sizeof(int));
14904  triangle_refine.segmentlist =
14905  (int *) malloc(triangulate_io.numberofsegments * 2 * sizeof(int));
14906  triangle_refine.segmentmarkerlist =
14907  (int *) malloc(triangulate_io.numberofsegments * sizeof(int));
14908 
14909  // Storing the point's coordinates in the list
14910  // and in two vectors with x and y coordinates
14911  Vector<double> x_coord (n_points);
14912  Vector<double> y_coord (n_points);
14913 
14914  for(unsigned count_point=0;count_point<n_points*2;count_point++)
14915  {
14916  triangle_refine.pointlist[count_point]=
14917  triangulate_io.pointlist[count_point];
14918 
14919  // Even vaules represent the x coordinate
14920  // Odd values represent the y coordinate
14921  if (count_point%2==0)
14922  {
14923  x_coord[count_point/2] = triangulate_io.pointlist[count_point];
14924  }
14925  else
14926  {
14927  y_coord[(count_point-1)/2] = triangulate_io.pointlist[count_point];
14928  }
14929  }
14930 
14931  // Store the point's markers in the list
14932  for(unsigned count_marker=0;count_marker<n_points;count_marker++)
14933  {
14934  triangle_refine.pointmarkerlist[count_marker]=
14935  triangulate_io.pointmarkerlist[count_marker];
14936  }
14937 
14938  // Storing the segment's edges in the list
14939  for(unsigned count_seg=0;count_seg<n_segments*2;count_seg++)
14940  {
14941  triangle_refine.segmentlist[count_seg]=
14942  triangulate_io.segmentlist[count_seg];
14943  }
14944 
14945  // Store the segment's markers in the list
14946  for(unsigned count_markers=0;count_markers<n_segments;count_markers++)
14947  {
14948  triangle_refine.segmentmarkerlist[count_markers]=
14949  triangulate_io.segmentmarkerlist[count_markers];
14950  }
14951 
14952  // Store the hole's center coordinates
14953  unsigned n_holes = triangulate_io.numberofholes;
14954  triangle_refine.numberofholes = n_holes;
14955 
14956  triangle_refine.holelist =
14957  (double*) malloc(triangulate_io.numberofholes * 2 * sizeof(double));
14958 
14959  // Loop over the holes to get centre coords
14960  for(unsigned count_hole=0;count_hole<n_holes*2;count_hole++)
14961  {
14962  triangle_refine.holelist[count_hole] = triangulate_io.holelist[count_hole];
14963  }
14964 
14965  // Store the triangles values
14966  unsigned n_triangles = triangulate_io.numberoftriangles;
14967  triangle_refine.numberoftriangles = n_triangles;
14968 
14969 #ifdef PARANOID
14970  if (n_triangles!=target_area.size())
14971  {
14972  std::stringstream err;
14973  err << "Number of triangles in triangulate_io="
14974  << n_triangles << " doesn't match\n"
14975  << "size of target area vector ("
14976  << target_area.size() << ")\n";
14977  throw OomphLibError(
14978  err.str(),
14979  OOMPH_CURRENT_FUNCTION,
14980  OOMPH_EXCEPTION_LOCATION);
14981  }
14982 #endif
14983 
14984  unsigned n_corners = triangulate_io.numberofcorners;
14985  triangle_refine.numberofcorners = n_corners;
14986 
14987  triangle_refine.trianglelist =
14988  (int *) malloc(triangulate_io.numberoftriangles * 3 * sizeof(int));
14989 
14990  // Store the triangle's corners in the list and get element sizes
14991  for(unsigned count_tri=0;count_tri<n_triangles*3;count_tri++)
14992  {
14993  triangle_refine.trianglelist[count_tri]=
14994  triangulate_io.trianglelist[count_tri];
14995  }
14996 
14997  // Store the triangle's area in the list
14998  triangle_refine.trianglearealist =
14999  (double *) malloc(triangulate_io.numberoftriangles * sizeof(double));
15000  for(unsigned count_area=0;count_area<n_triangles;count_area++)
15001  {
15002  triangle_refine.trianglearealist[count_area]=target_area[count_area];
15003  }
15004 
15005  // Store the triangles attributes in the list
15006  triangle_refine.numberoftriangleattributes =
15007  triangulate_io.numberoftriangleattributes;
15008 
15009  triangle_refine.triangleattributelist =
15010  (double *) malloc(
15011  triangulate_io.numberoftriangles *
15012  triangulate_io.numberoftriangleattributes * sizeof(double));
15013  for(unsigned count_attribute=0;
15014  count_attribute<(n_triangles*triangulate_io.numberoftriangleattributes);
15015  count_attribute++)
15016  {
15017  triangle_refine.triangleattributelist[count_attribute] =
15018  triangulate_io.triangleattributelist[count_attribute];
15019  }
15020 
15021  }
15022 
15023 #ifdef OOMPH_HAS_MPI
15024 
15025  // ===================================================================
15026  // The comparison class for the map that sorts the nodes on the
15027  // shared boundary (using a lexicographic order)
15028  // ===================================================================
15029  struct classcomp
15030  {
15031 
15032  // Tolerance for lower-left comparison
15033  static double Tol;
15034 
15035 
15036  // Comparison operator for "lower left" ordering
15037  bool operator() (const std::pair<double, double> &lhs,
15038  const std::pair<double, double> &rhs) const
15039  {
15040  double diff_y=lhs.second-rhs.second;
15041  if (diff_y<-Tol) // (lhs.second < rhs.second)
15042  {
15043  return true;
15044  }
15045  else
15046  {
15047  // Are they "equal" with 1.0e-14 tolerance?
15048  if (diff_y<Tol) // (lhs.second == rhs.second)
15049  {
15050 #ifdef PARANOID
15051  double diff_x=lhs.first-rhs.first;
15052  if (fabs(diff_x)<Tol)
15053  {
15054  std::ostringstream warning_message;
15055  warning_message
15056  << "Dodgy \"lower left\" (lexicographic) comparison "
15057  << "of points with cooordinates: "
15058  << " lhs = ( " << lhs.first << " , " << lhs.second << " ) \n"
15059  << " rhs = ( " << rhs.first << " , " << rhs.second << " ) \n"
15060  << "x and y coordinates differ by less than tolerance!\n"
15061  << "diff_x = " << diff_x << "\n"
15062  << "diff_y = " << diff_y << "\n"
15063  << "Tol = " << Tol << "\n";
15064  OomphLibError(warning_message.str(),
15065  OOMPH_CURRENT_FUNCTION,
15066  OOMPH_EXCEPTION_LOCATION);
15067  }
15068 #endif
15069  if (lhs.first < rhs.first)
15070  {
15071  return true;
15072  }
15073  else
15074  {
15075  return false;
15076  }
15077  }
15078  else
15079  {
15080  return false;
15081  }
15082  }
15083 
15084 
15085 
15086  // if (lhs.second < rhs.second)
15087  // {
15088  // return true;
15089  // }
15090  // else
15091  // {
15092  // // // Are "equal" with 1.0e-14 tolerance
15093  // // if (lhs.second - rhs.second < 1.0e-14)
15094  // // Are equal?
15095  // if (lhs.second == rhs.second)
15096  // {
15097  // if (lhs.first < rhs.first)
15098  // {
15099  // return true;
15100  // }
15101  // else
15102  // {
15103  // return false;
15104  // }
15105  // }
15106  // else
15107  // {
15108  // return false;
15109  // }
15110  // }
15111 
15112 
15113  }
15114 
15115  } Bottom_left_sorter; // struct classcomp
15116 
15117 
15118  // Assign value for tolerance
15119  double classcomp::Tol=1.0e-14;
15120 
15121 
15122  //======================================================================
15123  // Sort the nodes on shared boundaries so that the processors that share
15124  // a boundary agree with the order of the nodes on the boundary
15125  //======================================================================
15126  template <class ELEMENT>
15128  {
15129  // Get the shared boundaries in this processor
15130  Vector<unsigned> my_rank_shared_boundaries_ids;
15131  this->shared_boundaries_in_this_processor(my_rank_shared_boundaries_ids);
15132 
15133  // Get the number of shared boundaries
15134  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
15135 
15136  // Loop over the shared boundaries
15137  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
15138  {
15139  // A map is used to sort the nodes using their coordinates as the key
15140  // of the map
15141  //std::map<std::pair<double, double>, Node*> sorted_nodes_pt;
15142  std::map<std::pair<double, double>, Node*, classcomp> sorted_nodes_pt;
15143 
15144 
15145 #ifdef PARANOID
15146 
15147  // Check min distance between nodes; had better be less than the
15148  // tolerance used for the bottom left sorting
15149  double min_distance_squared=DBL_MAX;
15150 
15151 #endif
15152 
15153  // Get the boundary id
15154  const unsigned b = my_rank_shared_boundaries_ids[i];
15155 
15156  // Get the number of nodes on the current boundary
15157  const unsigned nbnd_node = this->nshared_boundary_node(b);
15158 
15159  // Go through all the nodes on the boundary and temporarily store
15160  // them on the map container
15161  for (unsigned i_node = 0; i_node < nbnd_node; i_node++)
15162  {
15163  Node* node_pt = this->shared_boundary_node_pt(b, i_node);
15164  std::pair<double, double> vertex = std::make_pair(node_pt->x(0),
15165  node_pt->x(1));
15166  sorted_nodes_pt[vertex] = node_pt;
15167 
15168 
15169 
15170 #ifdef PARANOID
15171 
15172  // Check for minimum distance
15173  for (unsigned j_node = 0; j_node < nbnd_node; j_node++)
15174  {
15175  if (i_node!=j_node)
15176  {
15177  Node* node2_pt = this->shared_boundary_node_pt(b, j_node);
15178 
15179  // Squared distance
15180  double squared_distance=0.0;
15181  for (unsigned ii=0;ii<2;ii++)
15182  {
15183  squared_distance+=
15184  (node_pt->x(ii)-node2_pt->x(ii))*
15185  (node_pt->x(ii)-node2_pt->x(ii));
15186  }
15187  if (squared_distance<min_distance_squared)
15188  {
15189  min_distance_squared=squared_distance;
15190  }
15191  }
15192  }
15193 
15194  if (sqrt(min_distance_squared)<Bottom_left_sorter.Tol)
15195  {
15196  std::ostringstream warning_message;
15197  warning_message
15198  << "Minimum distance between nodes on boundary " << b << "\n"
15199  << "is " << sqrt(min_distance_squared) << " which is less than "
15200  << "Bottom_left_sorter.Tol = " << Bottom_left_sorter.Tol << "\n"
15201  << "This may screw up the ordering of the nodes on shared boundaries\n";
15202  OomphLibWarning(warning_message.str(),
15203  OOMPH_CURRENT_FUNCTION,
15204  OOMPH_EXCEPTION_LOCATION);
15205  }
15206 
15207 #endif
15208 
15209  }
15210 
15211  unsigned counter = 0;
15212  // Resize the sorted shared boundary node vector
15213  this->Sorted_shared_boundary_node_pt[b].resize(nbnd_node);
15214 
15215  // Now go through the map container, get the elements and store their
15216  // members on the Sorted_shared_boundary_node_pt container
15217  // The map has already sorted the nodes, now they keep the same sorting
15218  // on all processors
15219  for (std::map<std::pair<double, double>, Node*>::iterator it_map
15220  = sorted_nodes_pt.begin(); it_map != sorted_nodes_pt.end(); it_map++)
15221  {
15222  // Store the pointer to the node
15223  this->Sorted_shared_boundary_node_pt[b][counter++] = (*it_map).second;
15224  }
15225 
15226  } // for (i < nmy_rank_shd_bnd)
15227 
15228  }
15229 
15230  //========================================================================
15231  // Re-establish the shared boundary elements after the adaptation
15232  // process (the updating of shared nodes is optional and performed by
15233  // default)
15234  //========================================================================
15235  template <class ELEMENT>
15238  const bool update_elements,
15239  const bool flush_nodes,
15240  const bool update_nodes)
15241  {
15242  // Get the rank of the current processor
15243  const unsigned my_rank = this->communicator_pt()->my_rank();
15244 
15245  // Go through the boundaries know as shared boundaries and copy the
15246  // elements to the corresponding storage
15247 
15248  // Get the initial shared boundary id
15249  const unsigned initial_id = this->initial_shared_boundary_id();
15250 
15251  // Get the final shared boundary id
15252  const unsigned final_id = this->final_shared_boundary_id();
15253 
15254  if (flush_elements)
15255  {
15256  // Flush the shared boundaries storage for elements
15257  this->flush_shared_boundary_element();
15258  // .. and also flush the face indexes associated with the element
15259  this->flush_face_index_at_shared_boundary();
15260  } // if (flush_elements)
15261 
15262  if (flush_nodes)
15263  {
15264  // Flush the shared boundaries storage for nodes
15265  this->flush_shared_boundary_node();
15266  } // if (flush_nodes)
15267 
15268  for (unsigned b = initial_id; b < final_id; b++)
15269  {
15270  // Check if the boundary is on the current processor
15271  Vector<unsigned> procs_from_shrd_bnd;
15272  procs_from_shrd_bnd = this->shared_boundary_from_processors(b);
15273  bool current_processor_has_b_boundary = false;
15274  const unsigned n_procs_from_shrd_bnd = procs_from_shrd_bnd.size();
15275  for (unsigned p = 0; p < n_procs_from_shrd_bnd; p++)
15276  {
15277  if (procs_from_shrd_bnd[p] == my_rank)
15278  {
15279  current_processor_has_b_boundary = true;
15280  break; // break for (p < n_procs_from_shrd_bnd)
15281  }
15282  } // for (p < n_procs_from_shrd_bnd)
15283 
15284  if (current_processor_has_b_boundary)
15285  {
15286  if (update_elements)
15287  {
15288  const unsigned nboundary_ele = this->nboundary_element(b);
15289  for (unsigned e = 0; e < nboundary_ele; e++)
15290  {
15291  // Get the boundary element and add it to the shared
15292  // boundary elements structure
15293  FiniteElement* bnd_ele_pt = this->boundary_element_pt(b, e);
15294  this->add_shared_boundary_element(b, bnd_ele_pt);
15295  // ... do the same with the face index information
15296  int face_index = this->face_index_at_boundary(b, e);
15297  this->add_face_index_at_shared_boundary(b, face_index);
15298  } // for (e < nboundary_element)
15299  } // if (update_elements)
15300 
15301  if (update_nodes)
15302  {
15303 
15304 
15305  const unsigned nboundary_node = this->nboundary_node(b);
15306  for (unsigned n = 0; n < nboundary_node; n++)
15307  {
15308  Node* bnd_node_pt = this->boundary_node_pt(b, n);
15309  this->add_shared_boundary_node(b, bnd_node_pt);
15310  } // for (n < nboundary_node)
15311  } // if (update_nodes)
15312 
15313  } // if (current_processor_has_b_boundary)
15314  } // for (b < final_id)
15315 
15316  }
15317 
15318  //======================================================================
15319  // Sort the nodes on shared boundaries so that the processors that share
15320  // a boundary agree with the order of the nodes on the boundary
15321  //======================================================================
15322  template <class ELEMENT>
15324  {
15325  // Get the number of processors
15326  unsigned nproc = this->communicator_pt()->nproc();
15327  // Get the rank of the current processor
15328  unsigned my_rank = this->communicator_pt()->my_rank();
15329 
15330  // Get some timings
15331  double tt_start = 0.0;
15332  double tt_end=0.0;
15333  if (Global_timings::Doc_comprehensive_timings)
15334  {
15335  tt_start=TimingHelpers::timer();
15336  }
15337 
15338  // -------------------------------------------------------------------
15339  // BEGIN: Get the node names and the shared nodes
15340  // -------------------------------------------------------------------
15341 
15342  // Container where to store the nodes on shared boundaries no
15343  // associated with the processor that receives the elements/nodes
15344  // other_proc_shd_bnd_node_pt[iproc][jproc][shd_bnd_id][index]
15345  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
15346  other_proc_shd_bnd_node_pt(nproc);
15347  // Resize the container
15348  for (unsigned iproc = 0; iproc < nproc; iproc++)
15349  {
15350  // Resize the container
15351  other_proc_shd_bnd_node_pt[iproc].resize(nproc);
15352  for (unsigned jproc = 0; jproc < nproc; jproc++)
15353  {
15354  // Get the number of shared boundaries
15355  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
15356  const unsigned final_shd_bnd_id = this->final_shared_boundary_id();
15357  const unsigned nshared_bound = final_shd_bnd_id - initial_shd_bnd_id;
15358  other_proc_shd_bnd_node_pt[iproc][jproc].resize(nshared_bound);
15359  } // for (jproc < nproc)
15360 
15361  } // for (iproc < nproc)
15362 
15363  // Store the global node names
15364  // global_node_name[x][ ][ ] Global node number
15365  // global_node_name[ ][x][ ] Global node names
15366  // global_node_name[ ][ ][x] Global node info.
15367  Vector<Vector<Vector<unsigned> > > global_node_names;
15368 
15369  // Creates a map between the node name and the index of the global
15370  // node so we can access all its node names
15371  std::map<Vector<unsigned>, unsigned> node_name_to_global_index;
15372 
15373  // Store the global shared nodes pointers
15374  Vector<Node*> global_shared_node_pt;
15375 
15376  // Get the time for computation of global nodes names and shared
15377  // nodes
15378  double t_start_global_node_names_and_shared_nodes =
15379  TimingHelpers::timer();
15380 
15381  // Compute all the names of the nodes and fill in the
15382  // "other_proc_shd_bnd_node_pt" structure with the nodes that live
15383  // on this processor (my_rank) by looking over all their names
15384  compute_global_node_names_and_shared_nodes(other_proc_shd_bnd_node_pt,
15385  global_node_names,
15386  node_name_to_global_index,
15387  global_shared_node_pt);
15388 
15389  // Compute the number of elements before adding new ones
15390  const unsigned n_ele = this->nelement();
15391 
15392  if (Print_timings_level_adaptation>1)
15393  {
15394  // The total time for computation of global nodes names and
15395  // shared nodes
15396  double t_final_global_node_names_and_shared_nodes =
15397  TimingHelpers::timer() - t_start_global_node_names_and_shared_nodes;
15398  oomph_info << "CPU for computing global node names and shared nodes "
15399  << "[n_ele="<< n_ele << "]: "
15400  << t_final_global_node_names_and_shared_nodes << std::endl;
15401  }
15402 
15403  // -------------------------------------------------------------------
15404  // END: Get the node names and the shared nodes
15405  // -------------------------------------------------------------------
15406 
15407  // -------------------------------------------------------------------
15408  // BEGIN: Using the global node names each processor sends info. of
15409  // the nodes shared with other processors regarding whether they are
15410  // on an original boundary or not. This is required so that at the
15411  // re-generation of halo(ed) elements stage they have the updated
15412  // information
15413  // -------------------------------------------------------------------
15414 
15415  // Get the time for sending info. of shared nodes on original
15416  // boundaries
15417  double t_start_send_info_shd_nodes_on_original_bnds =
15418  TimingHelpers::timer();
15419 
15420  // Send the boundary node info. of nodes on shared boundaries across
15421  // processors
15422  send_boundary_node_info_of_shared_nodes(global_node_names,
15423  node_name_to_global_index,
15424  global_shared_node_pt);
15425 
15426  if (Print_timings_level_adaptation>1)
15427  {
15428  // The total time for sending info. of shared nodes lying on
15429  // original boundaries
15430  oomph_info
15431  <<"CPU for sending info. of shared nodes on original boundaries: "
15432  <<TimingHelpers::timer()-t_start_send_info_shd_nodes_on_original_bnds
15433  <<std::endl;
15434  }
15435 
15436  // -------------------------------------------------------------------
15437  // END: Using the global node names each processor sends info. of
15438  // the nodes shared with other processors regarding whether they are
15439  // on an original boundary or not. This is required so that at the
15440  // re-generation of halo(ed) elements stage they have the updated
15441  // information
15442  // -------------------------------------------------------------------
15443 
15444  // -------------------------------------------------------------------
15445  // BEGIN: Identify the elements of the mesh that have nodes on the
15446  // shared boundaries
15447  // -------------------------------------------------------------------
15448 
15449  // Store the elements that have a node on a shared boundary with
15450  // other processors
15451  // ele_with_node_on_shd_bnd_pt[x][ ][ ]: iproc
15452  // ele_with_node_on_shd_bnd_pt[ ][x][ ]: ishd boundary with iproc
15453  // ele_with_node_on_shd_bnd_pt[ ][ ][x]: element with node on shared
15454  // boundary with iproc
15455  Vector<Vector<Vector<FiniteElement*> > > ele_with_node_on_shd_bnd_pt(nproc);
15456  // Resize the container with the number of shared boundaries within
15457  // each processor
15458 
15459  // loop over the processors
15460  for (unsigned iproc = 0; iproc < nproc; iproc++)
15461  {
15462  const unsigned n_shd_bnd_iproc = this->nshared_boundaries(my_rank, iproc);
15463  ele_with_node_on_shd_bnd_pt[iproc].resize(n_shd_bnd_iproc);
15464  } // for (iproc < nproc)
15465 
15466  // Go through all the elements and check whether any of their nodes
15467  // lies on any of the shared boundaries
15468 
15469  // loop over the elements
15470  for (unsigned e = 0; e < n_ele; e++)
15471  {
15472  // Get the element
15473  FiniteElement* ele_pt = this->finite_element_pt(e);
15474  // Get the number of nodes
15475  const unsigned n_nodes = ele_pt->nnode();
15476  // loop over the nodes and check whether any of them lies on a
15477  // shared boundary
15478  for (unsigned n = 0; n < n_nodes; n++)
15479  {
15480  // Get the node
15481  Node* node_pt = ele_pt->node_pt(n);
15482 
15483  // Now check whether the current node lies on a shared boundary
15484  // within any other processor
15485 
15486  // loop over the processors
15487  for (unsigned iproc = 0; iproc < nproc; iproc++)
15488  {
15489  // The number of boundaries shared with the current processor
15490  // (if iproc==my_rank then there are no shared boundaries
15491  // between them)
15492  const unsigned n_shd_bnd_iproc =
15493  this->nshared_boundaries(my_rank, iproc);
15494 
15495  // There are no info. with myself
15496  if (iproc != my_rank && n_shd_bnd_iproc > 0)
15497  {
15498  // Get the boundaries ids of the shared boundaries with
15499  // iproc processor
15500  Vector<unsigned> shd_bnd_ids =
15501  this->shared_boundaries_ids(my_rank, iproc);
15502 
15503  // Loop over shd bnds with processor "iproc"
15504  for (unsigned isb = 0; isb < n_shd_bnd_iproc; isb++)
15505  {
15506  const unsigned shd_bnd_id = shd_bnd_ids[isb];
15507  const unsigned n_ele_shd_bnd =
15508  this->nshared_boundary_element(shd_bnd_id);
15509 
15510  // Check if the node is on this boundary only if there are
15511  // elements on it
15512  if (n_ele_shd_bnd > 0 &&
15513  this->is_node_on_shared_boundary(shd_bnd_id, node_pt))
15514  {
15515  // Add the element into those that have a
15516  // node on the current shared boundary
15517  ele_with_node_on_shd_bnd_pt[iproc][isb].push_back(ele_pt);
15518 
15519  } // Are there elements on the boundary and the node lies
15520  // on this boundary
15521 
15522  } // for (isb < n_shd_bnd_iproc)
15523 
15524  } // if (iproc != my_rank && n_shd_bnd_iproc > 0)
15525 
15526  } // for (iproc < nproc)
15527 
15528  } // for (n < n_nodes)
15529 
15530  } // for (e < n_ele)
15531 
15532  // -------------------------------------------------------------------
15533  // END: Identify the elements of the mesh that have nodes on the
15534  // shared boundaries
15535  // -------------------------------------------------------------------
15536 
15537  // -------------------------------------------------------------------
15538  // BEGIN: Create the halo(ed) elements. Loop over the processors and
15539  // the shared boundaries within each processor. Get the elements on
15540  // the shared boundaries, mark them as haloed in this processor and
15541  // as halo on the element that will receive the info.
15542  // -------------------------------------------------------------------
15543 
15544  // ********************************************************************
15545  // General strategy:
15546  // 1) Go through all the elements on the shared boundaries, mark these
15547  // elements as haloed, same as their nodes.
15548  // 2) Package the info. of the nodes and the elements.
15549  // 3) Send and receive the info across processors
15550  // 4) Unpackage it and create halo elements and nodes as indicated by
15551  // the received info.
15552  // ********************************************************************
15553 
15554  // Keep track of the currently created nodes within each
15555  // processor. We need to keep track of these nodes so they can be
15556  // referred at a second stage.
15557  Vector<Vector<Node*> > iproc_currently_created_nodes_pt(nproc);
15558 
15559  // Get the time to re-generate halo(ed) elements/nodes (first stage)
15560  double t_start_regenerate_halo_ed_elements_nodes_first_stage =
15561  TimingHelpers::timer();
15562 
15563  // Go through all processors
15564  for (unsigned iproc = 0; iproc < nproc; iproc++)
15565  {
15566  // Send and receive info. to/from other processors
15567  if (iproc != my_rank)
15568  {
15569  // Get the number of boundaries shared with the send proc (iproc)
15570  const unsigned nshared_boundaries_with_iproc =
15571  this->nshared_boundaries(my_rank, iproc);
15572 
15573  if (nshared_boundaries_with_iproc > 0)
15574  {
15575  // ******************************************************************
15576  // Stage 1
15577  // ******************************************************************
15578  // Step (1) Mark the elements adjacent to the shared boundaries as
15579  // haloed, mark the nodes on these elements as haloed nodes
15580  // Step (2) Create packages of information indicating the generation
15581  // of halo elements and nodes
15582  // ******************************************************************
15583 
15584  // Clean send and receive buffers
15585  Flat_packed_unsigneds.clear();
15586  Flat_packed_doubles.clear();
15587 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15588  Flat_packed_unsigneds_string.clear();
15589 #endif
15590 
15591  // Get the boundaries ids shared with "iproc"
15592  Vector<unsigned> bound_shared_with_iproc;
15593  bound_shared_with_iproc = this->shared_boundaries_ids(my_rank, iproc);
15594 
15595  // Loop over shared boundaries with processor "iproc"
15596  for (unsigned bs = 0; bs < nshared_boundaries_with_iproc; bs++)
15597  {
15598  const unsigned bnd_id = bound_shared_with_iproc[bs];
15599 // DEBP(bnd_id);
15600  const unsigned nel_bnd = this->nshared_boundary_element(bnd_id);
15601 // DEBP(nel_bnd);
15602 
15603  // Container to store the elements marked as haloed
15604  Vector<FiniteElement*> haloed_element;
15605 
15606  // All the elements adjacent to the boundary should be
15607  // marked as haloed elements
15608  if (nel_bnd > 0)
15609  {
15610  // Map to know which element have been already added
15611  std::map<FiniteElement*,bool> already_added;
15612 
15613  // Loop over the elements adjacent to boundary "bnd_id"
15614  for (unsigned e = 0; e < nel_bnd; e++)
15615  {
15616  // Get pointer to the element adjacent to boundary bnd_id
15617  FiniteElement* ele_pt =
15618  this->shared_boundary_element_pt(bnd_id, e);
15619 
15620  // Check if the element has been already added. Elemets
15621  // are repeated if they have two faces on the shared
15622  // boundary
15623  if (!already_added[ele_pt])
15624  {
15625  // Add the element to the container of haloed elements
15626  haloed_element.push_back(ele_pt);
15627  // Mark the element as already added
15628  already_added[ele_pt] = true;
15629  }
15630 
15631  } // for (e < nel_bnd)
15632 
15633  // In addition to the elements on the boundary we also
15634  // need to mark (as haloed) any element on the mesh with a
15635  // node on the shared boundary
15636 
15637  // Get the number of elements with a node on the current
15638  // shared boundary
15639  const unsigned n_ele_with_node_on_shd_bnd =
15640  ele_with_node_on_shd_bnd_pt[iproc][bs].size();
15641  // loop and add the elements that have a node on the
15642  // current shared boundary with the current processor
15643  for (unsigned iele = 0; iele < n_ele_with_node_on_shd_bnd; iele++)
15644  {
15645  // Get the element
15646  FiniteElement* ele_pt =
15647  ele_with_node_on_shd_bnd_pt[iproc][bs][iele];
15648  // Check if it has not been already added
15649  if (!already_added[ele_pt])
15650  {
15651  // Add it!!
15652  haloed_element.push_back(ele_pt);
15653  // Mark it as done
15654  already_added[ele_pt] = true;
15655  } // if (!already_added[ele_pt])
15656 
15657  } // for (iele < n_ele_with_node_on_shd_bnd)
15658 
15659  } // if (nel_bnd > 0)
15660 
15661  // Get the total number of haloed elements
15662  const unsigned nhaloed_ele = haloed_element.size();
15663  // DEBP(nhaloed_ele);
15664  // DEBP(my_rank);
15665  // DEBP(iproc);
15666  // The very first data of the flat packed is the number of haloed
15667  // elements, this will be the number of halo element to create on
15668  // the receiver processor
15669  Flat_packed_unsigneds.push_back(nhaloed_ele);
15670 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15671  std::stringstream junk;
15672  junk << "Number of haloed elements " << nhaloed_ele;
15673  Flat_packed_unsigneds_string.push_back(junk.str());
15674 #endif
15675 
15676  // Loop over the marked haloed elements
15677  for (unsigned e = 0; e < nhaloed_ele; e++)
15678  {
15679  // Get pointer to the marked haloed element
15680  FiniteElement* ele_pt = haloed_element[e];
15681  const unsigned nroot_haloed_ele =
15682  this->nroot_haloed_element(iproc);
15683 
15684  // Check if the element has been already added to the
15685  // halo(ed) scheme
15686  GeneralisedElement *gen_ele_pt = ele_pt;
15687  const unsigned haloed_ele_index =
15688  this->try_to_add_root_haloed_element_pt(iproc, gen_ele_pt);
15689 
15690  // Was the element added or only returned the index of the
15691  // element
15692  if (nroot_haloed_ele == haloed_ele_index)
15693  {
15694  Flat_packed_unsigneds.push_back(1);
15695 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15696  Flat_packed_unsigneds_string.push_back("Haloed element needs to be constructed");
15697 #endif
15698 
15699  // Get additional info. related with the haloed element
15700  get_required_elemental_information_helper(iproc, ele_pt);
15701 
15702  // Get the nodes on the element
15703  const unsigned nnodes = ele_pt->nnode();
15704  for (unsigned j = 0; j < nnodes; j++)
15705  {
15706  Node* node_pt = ele_pt->node_pt(j);
15707 
15708  // Package the info. of the nodes
15709  // The destination processor goes in the arguments
15710  add_haloed_node_helper(iproc, node_pt);
15711 
15712  } // for (j < nnodes)
15713  } // add the element and send its nodes
15714  else // The haloed element already exists
15715  {
15716  Flat_packed_unsigneds.push_back(0);
15717 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15718  Flat_packed_unsigneds_string.push_back("Haloed element already exists");
15719 #endif
15720  Flat_packed_unsigneds.push_back(haloed_ele_index);
15721 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15722  Flat_packed_unsigneds_string.push_back("Index of existing haloed element");
15723 #endif
15724  } // else (next_haloed_ele == external_haloed_ele_index)
15725  } // for (e < nel_bnd)
15726 
15727  } // for (bs < nshared_boundaries_with_iproc)
15728 
15729  // *******************************************************************
15730  // Stage (2)
15731  // *******************************************************************
15732  // Step (1) Send and receive the data to create halo elements and
15733  // nodes
15734  // *******************************************************************
15735  // The processor to which send the elements
15736  int send_proc = static_cast<int>(iproc);
15737  // The processor from which receive the elements
15738  int recv_proc = static_cast<int>(iproc);
15739  send_and_receive_elements_nodes_info(send_proc, recv_proc);
15740 
15741  // *******************************************************************
15742  // Stage (3)
15743  // *******************************************************************
15744  // Step (1) Unpackage the info and create the halo elements and nodes
15745  // *******************************************************************
15746 
15747  // Reset the counters
15748  Counter_for_flat_packed_doubles=0;
15749  Counter_for_flat_packed_unsigneds=0;
15750 
15751  // Loop over shared boundaries with processor "iproc"
15752  for (unsigned bs = 0; bs < nshared_boundaries_with_iproc; bs++)
15753  {
15754  // Get the number of halo element to be created
15755  const unsigned nhaloed_ele =
15756  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
15757 
15758 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15759  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
15760  << " Number of elements need to be constructed "
15761  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
15762  << std::endl;
15763 #endif
15764 
15765  // Loop over boundaries shared with processor "urecv_proc"
15766  for (unsigned e = 0; e < nhaloed_ele; e++)
15767  {
15768  // Create halo element from received info. of "iproc"
15769  // processor on the current processor
15770  create_halo_element(iproc,
15771  iproc_currently_created_nodes_pt[iproc],
15772  other_proc_shd_bnd_node_pt,
15773  global_node_names,
15774  node_name_to_global_index,
15775  global_shared_node_pt);
15776 
15777  } // for (e < nhaloed_ele)
15778 
15779  } // for (bs < nshared_boundaries_with_iproc)
15780 
15781  } // if (nshared_bound_recv_proc > 0)
15782 
15783  } // if (iproc != my_rank)
15784 
15785  } // for (iproc < nproc) (general loop to send and receive info.)
15786 
15787  if (Print_timings_level_adaptation>1)
15788  {
15789  // Get the time to re-generate halo(ed) elements/nodes (first stage)
15790  double t_final_regenerate_halo_ed_elements_nodes_first_stage =
15791  TimingHelpers::timer() - t_start_regenerate_halo_ed_elements_nodes_first_stage;
15792 
15793  oomph_info << "CPU for re-generating halo(ed) elements/nodes "
15794  << "(first stage) [n_ele="<< n_ele << "]: "
15795  << t_final_regenerate_halo_ed_elements_nodes_first_stage
15796  << std::endl;
15797  }
15798 
15799  // -------------------------------------------------------------------
15800  // END: Create the halo(ed) elements. Loop over the processors and
15801  // the shared boundaries within each processor. Get the elements on
15802  // the shared boundaries, mark them as haloed in this processor and
15803  // as halo on the element that will receive the info.
15804  // -------------------------------------------------------------------
15805 
15806  // -------------------------------------------------------------------
15807  // BEGIN: Create any additional haloed element, those that dont lie
15808  // on a shared boundary but that shared a node with other processor
15809  // -------------------------------------------------------------------
15810 
15811  // Get the time to re-generate halo(ed) elements/nodes (second stage)
15812  double t_start_regenerate_halo_ed_elements_nodes_second_stage =
15813  TimingHelpers::timer();
15814 
15815  // Create any additional halo(ed) elements between processors that
15816  // have no shared boundaries but that have shared nodes
15817  reset_halo_haloed_scheme_helper(other_proc_shd_bnd_node_pt,
15818  iproc_currently_created_nodes_pt,
15819  global_node_names,
15820  node_name_to_global_index,
15821  global_shared_node_pt);
15822 
15823  if (Print_timings_level_adaptation>1)
15824  {
15825  // Get the time to re-generate halo(ed) elements/nodes (second stage)
15826  double t_final_regenerate_halo_ed_elements_nodes_second_stage =
15827  TimingHelpers::timer() - t_start_regenerate_halo_ed_elements_nodes_second_stage;
15828 
15829  oomph_info << "CPU for re-generating halo(ed) elements/nodes "
15830  << "(second stage) [n_ele="<< n_ele << "]: "
15831  << t_final_regenerate_halo_ed_elements_nodes_second_stage
15832  << std::endl;
15833  }
15834 
15835  // -------------------------------------------------------------------
15836  // END: Create any additional haloed element, those that dont lie on
15837  // a shared boundary but that shared a node with other processor
15838  // -------------------------------------------------------------------
15839 
15840  // Clean send and receive buffers
15841  Flat_packed_unsigneds.clear();
15842  Flat_packed_doubles.clear();
15843 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
15844  Flat_packed_unsigneds_string.clear();
15845 #endif
15846 
15847  // Document the timings for reseting halo and haloed scheme (without
15848  // classification of halo and haloed nodes)
15849  if (Print_timings_level_adaptation>1)
15850  {
15851  tt_end = TimingHelpers::timer();
15852  oomph_info
15853  << "CPU for resetting halo-haloed scheme (without classification of halo and haloed nodes): "
15854  << tt_end-tt_start << std::endl;
15855  }
15856 
15857  // ------------------------------------------------------------------
15858  // BEGIN: Classify halo(ed) elements and nodes
15859  // ------------------------------------------------------------------
15860  const bool report_stats = true;
15861  DocInfo tmp_doc_info;
15862  tmp_doc_info.disable_doc();
15863 
15864  // Classify nodes
15865  this->classify_halo_and_haloed_nodes(tmp_doc_info,report_stats);
15866 
15867  // Document the timings for reseting halo and haloed scheme (with
15868  // classification of halo and haloed nodes)
15869  if (Print_timings_level_adaptation>1)
15870  {
15871  tt_end = TimingHelpers::timer();
15872  oomph_info
15873  << "CPU for resetting halo-haloed scheme (with classification of halo and haloed nodes): "
15874  << tt_end-tt_start << std::endl;
15875  }
15876 
15877  // ------------------------------------------------------------------
15878  // END: Classify halo(ed) elements and nodes
15879  // ------------------------------------------------------------------
15880 
15881  }
15882 
15883 //======================================================================
15884 // \short Compute the alias of the nodes on shared boundaries in this
15885 // (my_rank) processor with other processors. Also compute the alias
15886 // of nodes on shared boundaries of other processors with other
15887 // processors (useful when there is an element that requires to be
15888 // sent to this (my_rank) processor because there is a shared node
15889 // between this (my_rank) and other processors BUT there is not a
15890 // shared boundary between this and the other processor
15891 // ======================================================================
15892 template <class ELEMENT>
15895  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
15896  &other_proc_shd_bnd_node_pt,
15897  Vector<Vector<Vector<unsigned> > > &global_node_names,
15898  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
15899  Vector<Node*> &global_shared_node_pt)
15900 {
15901  // Get the number of processors
15902  const unsigned nproc = this->communicator_pt()->nproc();
15903  // Get the rank of the current processor
15904  const unsigned my_rank = this->communicator_pt()->my_rank();
15905  // Get the communicator of the mesh
15906  OomphCommunicator* comm_pt = this->communicator_pt();
15907 
15908  // ---------------------------------------------------------------
15909  // BEGIN: Get the elements adjacent to shared boundaries and give
15910  // a unique node number to the nodes on the shared boundaries in
15911  // this processor
15912  // ---------------------------------------------------------------
15913 
15914  // Counter for the nodes on shared boundaries in this (my_rank)
15915  // processor
15916  unsigned counter_nodes = 0;
15917  // Keep track of visited nodes
15918  std::map<Node*, bool> done_node;
15919  // ... and its local node number
15920  std::map<Node*, unsigned> local_node_number;
15921  // ... and the inverted relation from local node number to node_pt
15922  Vector<Node*> local_node_pt;
15923 
15924  // Stores the j-th node name associated with the i-th local node
15925  // on shared boundaries in this processor (my_rank)
15926  // local_node_names[i][j][0] = my_rank (this processor)
15927  // local_node_names[i][j][1] = iproc (the processor with which there
15928  // is a shared boundary)
15929  // local_node_names[i][j][2] = the shared boundary id between this
15930  // (my_rank) processor and iproc
15931  // processor
15932  // local_node_names[i][j][3] = the node index on the shared boundary
15933  // local_node_names[i][j][4] = the local node index (i). This may
15934  // be unnecessary since we alread know the
15935  // index but we also send this info. to
15936  // the root processor that is why we store
15937  // them here
15938  Vector<Vector<Vector<unsigned> > > local_node_names;
15939 
15940  // loop over the processors
15941  for (unsigned iproc = 0; iproc < nproc; iproc++)
15942  {
15943  // There are not shared boundaries with myself
15944  if (iproc != my_rank)
15945  {
15946  // Get the number of shared boundaries with iproc
15947  const unsigned n_shd_bnds_with_iproc =
15948  this->nshared_boundaries(my_rank, iproc);
15949 
15950  // Get the boundaries ids shared with iproc
15951  Vector<unsigned> bnd_shd_with_iproc =
15952  this->shared_boundaries_ids(my_rank, iproc);
15953 
15954  // Loop over the shared boundaries with processor iproc
15955  for (unsigned ishd = 0; ishd < n_shd_bnds_with_iproc; ishd++)
15956  {
15957  // Keep track of visited nodes with this shared boundary
15958  std::map<Node*,bool> done_node_shd_bnd;
15959  // The boundary id
15960  unsigned shd_bnd_id = bnd_shd_with_iproc[ishd];
15961  // Get the number of element on the shared boundary
15962  const unsigned n_shd_bnd_ele =
15963  this->nshared_boundary_element(shd_bnd_id);
15964 
15965  // loop over the elements adjacent to the shared boundary
15966  for (unsigned e = 0; e < n_shd_bnd_ele; e++)
15967  {
15968  // Get the element
15969  FiniteElement* ele_pt =
15970  this->shared_boundary_element_pt(shd_bnd_id, e);
15971 
15972  // Get the number of nodes on the element
15973  const unsigned n_nodes = ele_pt->nnode();
15974 
15975  // loop over the nodes of the current element
15976  for (unsigned n = 0; n < n_nodes; n++)
15977  {
15978  // Get the node
15979  Node* node_pt = ele_pt->node_pt(n);
15980 
15981  // Has the node been visited with this shared boundary?
15982  // And, is this a node on the shd_bnd_id shared boundary
15983  // with processor iproc?
15984  if (!done_node_shd_bnd[node_pt] &&
15985  this->is_node_on_shared_boundary(shd_bnd_id,
15986  node_pt))
15987  {
15988  // Mark the done as done with this shared boundary
15989  done_node_shd_bnd[node_pt] = true;
15990 
15991  // Get the index of the node on the shared boundary
15992  // -------------------------------------------------
15993  // Get the number of nodes on the shared boundary
15994  const unsigned n_nodes_shd_bnd =
15995  nsorted_shared_boundary_node(shd_bnd_id);
15996 
15997  // The index
15998  unsigned index = 0;
15999 
16000 #ifdef PARANOID
16001  // Flag to know if the node has been found
16002  bool found_node_on_shared_boundary = false;
16003 #endif
16004  // Loop over the nodes on the shared boundary to find
16005  // the node
16006  for (unsigned k = 0; k < n_nodes_shd_bnd; k++)
16007  {
16008  // Get the k-th node on the shared boundary
16009  Node* shd_bnd_node_pt =
16010  sorted_shared_boundary_node_pt(shd_bnd_id, k);
16011 
16012  // Is the same node?
16013  if (shd_bnd_node_pt == node_pt)
16014  {
16015  // This is the index
16016  index = k;
16017 #ifdef PARANOID
16018  // Mark as found
16019  found_node_on_shared_boundary = true;
16020 #endif
16021  break; // break
16022 
16023  } // if (shd_bnd_node_pt == node_pt)
16024 
16025  } // for (k < n_nodes_shd_bnd)
16026 
16027 #ifdef PARANOID
16028  if (!found_node_on_shared_boundary)
16029  {
16030  std::ostringstream error_message;
16031  error_message
16032  <<"The index of the node on boundary ("<<shd_bnd_id
16033  <<") was not found.\n"
16034  <<"These are the node coordinates\n"
16035  <<"("<<node_pt->x(0)<<","<<node_pt->x(1)<<").\n";
16036  throw OomphLibError(error_message.str(),
16037  OOMPH_CURRENT_FUNCTION,
16038  OOMPH_EXCEPTION_LOCATION);
16039  }
16040 #endif
16041 
16042  // Create the node name
16043  Vector<unsigned> node_name(5);
16044  node_name[0] = my_rank;
16045  node_name[1] = iproc;
16046  node_name[2] = shd_bnd_id;
16047  node_name[3] = index;
16048  // The node number is filled in the following if/else
16049  //node_name[4] = ?;
16050 
16051  // Has the node already been visited?
16052  if (!done_node[node_pt])
16053  {
16054  // If not ...
16055 
16056  // Add the node to the local nodes
16057  local_node_pt.push_back(node_pt);
16058 
16059  // Assign a local node number to the node
16060  local_node_number[node_pt] = counter_nodes;
16061  // Store the local node number
16062  node_name[4] = counter_nodes;
16063  // Increase the counter of nodes
16064  counter_nodes++;
16065  // ... and mark it as visited
16066  done_node[node_pt] = true;
16067 
16068  // Push back the node name (the first
16069  // one found for this node)
16070  Vector<Vector<unsigned> > first_node_name(1);
16071  first_node_name[0] = node_name;
16072  local_node_names.push_back(first_node_name);
16073  }
16074  else
16075  {
16076  // If yes ...
16077 
16078  // Get the local node number
16079  unsigned node_number = local_node_number[node_pt];
16080 
16081  // Store the local node number
16082  node_name[4] = node_number;
16083 
16084  // Push back the node name for the
16085  // node number
16086  local_node_names[node_number].push_back(node_name);
16087 
16088  }
16089 
16090  } // Is on shared boundary?
16091 
16092  } // for (n < nnodes)
16093 
16094  } // for (e < n_shd_bnd_ele)
16095 
16096  } // for (ishd < n_shd_bnds_with_iproc)
16097 
16098  } // if (iproc != my_rank)
16099 
16100  } // for (iproc < nproc)
16101 
16102  // ---------------------------------------------------------------
16103  // END: Get the elements adjacent to shared boundaries and give
16104  // a unique node number to the nodes on the shared boundaries in
16105  // this processor
16106  // ---------------------------------------------------------------
16107 
16108  // ---------------------------------------------------------------
16109  // BEGIN: Package the names of the local nodes
16110  // ---------------------------------------------------------------
16111  // Counter for the number of names of the nodes
16112  unsigned n_total_local_names = 0;
16113  // Get the number of local nodes
16114  const unsigned n_local_nodes = local_node_names.size();
16115  // loop over the number of local nodes and get the number of names
16116  // of each node
16117  for (unsigned i = 0; i < n_local_nodes; i++)
16118  {
16119  // Get the number of names of the i-th local node
16120  const unsigned n_inode_names = local_node_names[i].size();
16121  // ... and add them to the total number of local names
16122  n_total_local_names+=n_inode_names;
16123  } // for (i < n_local_nodes)
16124 
16125  // We store five data per node name (my_rank,iproc,shd_bnd_id,idx,node#)
16126  // where node# is the node number on this processor (my_rank)
16127  const unsigned n_info_per_node_name = 5;
16128  // Storage for the flat package
16129  Vector<unsigned> flat_packed_send_udata(n_total_local_names*n_info_per_node_name);
16130  // A counter
16131  unsigned counter = 0;
16132  // loop over the local nodes
16133  for (unsigned i = 0; i < n_local_nodes; i++)
16134  {
16135  // Get the number of names of the i-th local node
16136  const unsigned n_inode_names = local_node_names[i].size();
16137  // loop over the names of the i-th local node
16138  for (unsigned j = 0 ; j < n_inode_names; j++)
16139  {
16140  // Store this processor id (my_rank)
16141  flat_packed_send_udata[counter++]=local_node_names[i][j][0];
16142  // Store the processor with which the shared boundary exist
16143  flat_packed_send_udata[counter++]=local_node_names[i][j][1];
16144  // Store the shared boundary id
16145  flat_packed_send_udata[counter++]=local_node_names[i][j][2];
16146  // Store the index of the node on the shared boundary
16147  flat_packed_send_udata[counter++]=local_node_names[i][j][3];
16148  // Store the local node number on this processor (my_rank)
16149  flat_packed_send_udata[counter++]=local_node_names[i][j][4];
16150  } // for (j < n_inode_names)
16151 
16152  } // for (i < n_local_nodes)
16153 
16154  // Reset the counter
16155  counter = 0;
16156 
16157  // The number of data that will be sent to root from this
16158  // (my_rank) processor
16159  const unsigned n_udata_send_to_root = flat_packed_send_udata.size();
16160 
16161  // ---------------------------------------------------------------
16162  // END: Package the names of the local nodes
16163  // ---------------------------------------------------------------
16164  // ---------------------------------------------------------------
16165  // BEGIN: Send the data to the root processor
16166  // ---------------------------------------------------------------
16167 
16168  // The root processor is in charge of computing all the node names
16169  // of the nodes on the shared boundaries
16170 
16171  // Choose the root processor
16172  const unsigned root_processor = 0;
16173 
16174  // The vector where the root processor receives how many names
16175  // will receive from the other processors
16176  Vector<unsigned> root_n_names_per_processor(nproc);
16177 
16178  // Send the number of names that the root processor will receive
16179  // from each processor
16180  MPI_Gather(&n_total_local_names, 1, MPI_UNSIGNED,
16181  &root_n_names_per_processor[0], 1, MPI_UNSIGNED,
16182  root_processor, comm_pt->mpi_comm());
16183 
16184  // Get the total number of data to receive from all processor in
16185  // root
16186  unsigned root_n_total_udata_receive = 0;
16187  Vector<int> root_n_udata_to_receive(nproc,0);
16188  for (unsigned iproc = 0; iproc < nproc; iproc++)
16189  {
16190  root_n_udata_to_receive[iproc]=
16191  root_n_names_per_processor[iproc]*n_info_per_node_name;
16192  root_n_total_udata_receive+=root_n_udata_to_receive[iproc];
16193  }
16194 
16195  // Stores and compute the offsets (in root) for the data received
16196  // from each processor
16197  Vector<int> root_uoffsets_receive(nproc,0);
16198  root_uoffsets_receive[0] = 0;
16199  for (unsigned iproc = 1; iproc < nproc; iproc++)
16200  {
16201  // Compute the offset to obtain the data from each processor
16202  root_uoffsets_receive[iproc] =
16203  root_uoffsets_receive[iproc-1] + root_n_udata_to_receive[iproc-1];
16204 
16205  }
16206 
16207  // Create at least one entry so we don't get a seg fault below
16208  if (flat_packed_send_udata.size()==0)
16209  {
16210  flat_packed_send_udata.resize(1);
16211  }
16212 
16213  // Vector where to receive the info on root from all processors
16214  Vector<unsigned> root_flat_packed_receive_udata(root_n_total_udata_receive);
16215  // Only root receive data, the others dont, then resize the
16216  // container to have at least one entry
16217  if (my_rank!=root_processor)
16218  {
16219  // Create at least one entry so we don't get a seg fault below
16220  if (root_flat_packed_receive_udata.size()==0)
16221  {
16222  root_flat_packed_receive_udata.resize(1);
16223  }
16224  } // if (my_rank!=root_processor)
16225 
16226  // Send the info. to the root processor
16227  MPI_Gatherv(&flat_packed_send_udata[0], // Flat package to send
16228  // info. from each
16229  // processor
16230  n_udata_send_to_root, // Total number of data send
16231  // from each processor to root
16232  MPI_UNSIGNED,
16233  &root_flat_packed_receive_udata[0], // Container where
16234  // to receive the
16235  // info. from all
16236  // processors
16237  &root_n_udata_to_receive[0], // Number of data to
16238  // receive from each
16239  // processor
16240  &root_uoffsets_receive[0], // The offset to store the
16241  // info. from each
16242  // processor
16243  MPI_UNSIGNED,
16244  root_processor, //The processor that receives all the
16245  //info.
16246  comm_pt->mpi_comm());
16247 
16248  // Clear and resize the flat package to send
16249  flat_packed_send_udata.clear();
16250  flat_packed_send_udata.resize(0);
16251  // ---------------------------------------------------------------
16252  // END: Send the data to the root processor
16253  // ---------------------------------------------------------------
16254 
16255  // Container where root stores the info. that will be sent to all
16256  // processors. This includes the number of global nodes, the
16257  // number of names for each global node and the names
16258  Vector<unsigned> flat_packed_root_send_receive_udata;
16259 
16260  // ---------------------------------------------------------------
16261  // BEGIN: Unpackage the info. received on root. Compute the alias
16262  // of the nodes
16263  // ---------------------------------------------------------------
16264  if (my_rank == root_processor)
16265  {
16266  // Compute all the names of a node
16267  // root_global_node_name[x][ ][ ] Global node number
16268  // root_global_node_name[ ][x][ ] Global node names
16269  // root_global_node_name[ ][ ][x] Global node info.
16270  Vector<Vector<Vector<unsigned> > > root_global_node_names;
16271 
16272  // Store the info. extracted from the flat package sent to
16273  // root
16274  // root_local_node_names[x][ ] Node name
16275  // root_local_node_names[ ][x] Node info
16276  Vector<Vector<unsigned> > root_local_node_names;
16277 
16278  // Extract all the node names
16279  unsigned rcounter = 0;
16280  // loop over the processors
16281  for (unsigned iproc = 0; iproc < nproc; iproc++)
16282  {
16283  // Get the number of node names received from iproc
16284  const unsigned n_local_names_iproc =
16285  root_n_names_per_processor[iproc];
16286  for (unsigned i = 0; i < n_local_names_iproc; i++)
16287  {
16288  // Get the i-thnode name from iproc
16289  Vector<unsigned> node_name(n_info_per_node_name);
16290  for (unsigned j = 0; j < n_info_per_node_name; j++)
16291  {node_name[j] = root_flat_packed_receive_udata[rcounter++];}
16292 
16293  // Add the i-th node name
16294  root_local_node_names.push_back(node_name);
16295 
16296  } // for (i < n_local_names_iproc)
16297 
16298  } // for (iproc < nproc)
16299 
16300  // Get the number of node names received
16301  const unsigned n_root_local_node_names =
16302  root_local_node_names.size();
16303 
16304  // For each name of the node identify the position of its
16305  // counter-part
16306 
16307  // Given a node name on the iproc,
16308  // (iproc, jproc, ishd_bnd, idx, local_node_number1)
16309  // its counter part must live in jproc, so we look for the
16310  // node name
16311  // (jproc, iproc, ishd_bnd, idx, local_node_number2)
16312 
16313  // Store the index of the node name counter-part
16314  Vector<unsigned> node_name_counter_part(n_root_local_node_names);
16315 
16316  // Keep track of the names of nodes already done
16317  std::map<Vector<unsigned>, bool> done_name;
16318 
16319  // loop over the names of the nodes received from all
16320  // processors
16321  for (unsigned i = 0; i < n_root_local_node_names; i++)
16322  {
16323  // Get the i-th node name
16324  Vector<unsigned> node_name = root_local_node_names[i];
16325 
16326  // Check if this name node has been already done
16327  if (!done_name[node_name])
16328  {
16329  // Mark it as done
16330  done_name[node_name] = true;
16331 #ifdef PARANOID
16332  // Flag to indicate the counter-part name node was
16333  // found
16334  bool found_both_names_node = false;
16335 #endif
16336  // Find the counter-part name node (start from j+1
16337  // since all previous have been found, otherwise we
16338  // would not be here)
16339  for (unsigned j = i+1; j < n_root_local_node_names; j++)
16340  {
16341  Vector<unsigned> node_name_r = root_local_node_names[j];
16342 
16343  // Check if this name node has been already done
16344  if (!done_name[node_name_r])
16345  {
16346  // Check whether this node is the
16347  // counter-part of the current name node
16348  if (node_name[0] == node_name_r[1] &&
16349  node_name[1] == node_name_r[0] &&
16350  node_name[2] == node_name_r[2] &&
16351  node_name[3] == node_name_r[3])
16352  {
16353  // Mark the name as node
16354  done_name[node_name_r] = true;
16355  // Store the index of the counter-part of
16356  // the current node name
16357  node_name_counter_part[i] = j;
16358  // ... and indicate the current node name
16359  // as the index of the counter-part
16360  node_name_counter_part[j] = i;
16361 #ifdef PARANOID
16362  // The node has been found
16363  found_both_names_node = true;
16364 #endif
16365  // Break the loop to find the
16366  // counter-part
16367  break;
16368  }
16369 
16370  } // if (!done_name[node_name_r])
16371 
16372  } // for (j < n_root_local_node_names)
16373 #ifdef PARANOID
16374  // Check whether the node counter-part was found
16375  if (!found_both_names_node)
16376  {
16377  std::ostringstream error_message;
16378  error_message
16379  <<"The counter-part of the current name node was "
16380  <<"not found,\nthe current node name is:\n"
16381  <<"iproc:("<<node_name[0]<<")\n"
16382  <<"jproc:("<<node_name[1]<<")\n"
16383  <<"ishd_bnd:("<<node_name[2]<<")\n"
16384  <<"index:("<<node_name[3]<<")\n";
16385  throw OomphLibError(error_message.str(),
16386  OOMPH_CURRENT_FUNCTION,
16387  OOMPH_EXCEPTION_LOCATION);
16388  } // if (!found_both_names_node)
16389 #endif
16390 
16391  } // if (!done_name[node_name])
16392 
16393  } // for (i < n_root_local_node_names)
16394 
16395  // -----------------------------------------------------------
16396  // Look for all the names of each node received and store them
16397  // in the "global node names" container
16398 
16399  // Keep track of the names of nodes already done
16400  done_name.clear();
16401  // loop over the names of the nodes received from all
16402  // processors
16403  for (unsigned i = 0; i < n_root_local_node_names; i++)
16404  {
16405  // Get the i-th node name
16406  Vector<unsigned> node_name = root_local_node_names[i];
16407 
16408  // Check if this name node has been already done
16409  if (!done_name[node_name])
16410  {
16411  // Store all the names of the current node
16412  Vector<Vector<unsigned> > all_node_names;
16413 
16414  // Add the name of the node as the initial node name
16415  all_node_names.push_back(node_name);
16416 
16417  // Get the index of the counter-part
16418  unsigned idx_c = node_name_counter_part[i];
16419  // Get the counter-part of the node name
16420  Vector<unsigned> node_name_r = root_local_node_names[idx_c];
16421 
16422  // Add the name of the counter-part of the node
16423  all_node_names.push_back(node_name_r);
16424  // We do not mark it as done since we are interested in
16425  // the names that the counter-part may generate
16426 
16427  // Get the number of names for the current node (two at
16428  // the first time)
16429  unsigned n_current_names = all_node_names.size();
16430  // Counter to ensure to visit all the names of the current
16431  // node
16432  unsigned icounter = 0;
16433 
16434  // Visit all the names of the current node
16435  while(icounter < n_current_names)
16436  {
16437  // Get the current node name
16438  Vector<unsigned> current_node_name = all_node_names[icounter];
16439 
16440  // Search for other names for the current name of the
16441  // node, but first check if this has been already
16442  // visited
16443  if (!done_name[current_node_name])
16444  {
16445  // Mark it as done
16446  done_name[current_node_name] = true;
16447 
16448  // loop over the names of the nodes (start from the
16449  // j+1 position, all previous node names have all
16450  // their names already assigned)
16451  for (unsigned j=i+1;j<n_root_local_node_names;j++)
16452  {
16453  // Get the j-th node name
16454  Vector<unsigned> other_node_name = root_local_node_names[j];
16455 
16456  // Is this name node already done
16457  if (!done_name[other_node_name])
16458  {
16459  // Is this another name for the current name node?
16460  if ((current_node_name[0] == other_node_name[0]) &&
16461  (current_node_name[4] == other_node_name[4]))
16462  {
16463  // Mark it as done. If we search again using the
16464  // "other_node_name" as the current node name we
16465  // are not going to find new nodes to add
16466  done_name[other_node_name] = true;
16467  // Before adding it check that it is not already
16468  // part of the names of the node
16469  Vector<Vector<unsigned> >::iterator it
16470  = std::find(all_node_names.begin(),
16471  all_node_names.end(),
16472  other_node_name);
16473  if (it==all_node_names.end())
16474  {
16475  all_node_names.push_back(other_node_name);
16476  // Get the index of the counter-part
16477  unsigned k = node_name_counter_part[j];
16478  // Get the counter-part of the node name
16479  Vector<unsigned> other_node_name_r =
16480  root_local_node_names[k];
16481  // Add the name of the counter-part of the
16482  // node only if it has not been previously
16483  // done
16484  if (!done_name[other_node_name_r])
16485  {
16486  all_node_names.push_back(other_node_name_r);
16487  }
16488 
16489  }
16490 
16491  } // // Is this another name for the current name
16492  // node?
16493 
16494  } // if (!done_name[other_node_name])
16495 
16496  } // for (j < n_root_local_node_names)
16497 
16498  } // if (!done_name[current_node_name])
16499 
16500  // Get the number of names
16501  n_current_names = all_node_names.size();
16502  // Increase the icounter to indicate we have visited the
16503  // current name of the node
16504  icounter++;
16505 
16506  } // while(icounter < n_current_names)
16507 
16508  // We now have all the names for the i-th global node
16509  root_global_node_names.push_back(all_node_names);
16510 
16511  } // if (!done_name[node_name])
16512 
16513  } // for (i < n_root_local_node_names)
16514 
16515  // -------------------------------------------------------------
16516  // Prepare the info to be sent to all processors. The number
16517  // of global nodes, the number of names for each global node,
16518  // and their respective names
16519  // -------------------------------------------------------------
16520 
16521  // Clear the container
16522  flat_packed_root_send_receive_udata.clear();
16523  // Get the number of global nodes
16524  const unsigned n_global_nodes = root_global_node_names.size();
16525  // ... and store this info. to be sent from root to all
16526  // processors
16527  flat_packed_root_send_receive_udata.push_back(n_global_nodes);
16528 
16529  // loop over the nodes
16530  for (unsigned i = 0; i < n_global_nodes; i++)
16531  {
16532  // Get the names of the i-th global node
16533  Vector<Vector<unsigned> > global_inode_names =
16534  root_global_node_names[i];
16535  // Get the number of names for the i-th global node
16536  const unsigned n_names_global_inode = global_inode_names.size();
16537  // ... and store this info. to be sent from root to all
16538  // processors
16539  flat_packed_root_send_receive_udata.push_back(n_names_global_inode);
16540  // loop over the names of the global i-th node
16541  for (unsigned j = 0; j < n_names_global_inode; j++)
16542  {
16543  // loop over the info. associated with each name
16544  for (unsigned k = 0; k < n_info_per_node_name; k++)
16545  {
16546  // Store the name info. of the current name in the
16547  // container to be sent from root to all processors
16548  flat_packed_root_send_receive_udata.
16549  push_back(global_inode_names[j][k]);
16550  } // for (k < n_info_per_node_name)
16551 
16552  } // for (j < n_names_inode)
16553 
16554  } // for (i < n_global_nodes)
16555 
16556  } // if (my_rank == root_processor)
16557 
16558  // ----------------------------------------------------------------
16559  // END: Unpackage the info. received on root. Compute the alias
16560  // of the nodes and prepare the info. to be sent back from
16561  // root to all processors
16562  // ----------------------------------------------------------------
16563 
16564  // ---------------------------------------------------------------
16565  // BEGIN: Send the info. back to all processors, unpackage the
16566  // info. and create the map from node name to global node
16567  // index
16568  // ---------------------------------------------------------------
16569  // The number of data that root send to other processors.
16570  unsigned root_n_udata_sent_to_all_proc =
16571  flat_packed_root_send_receive_udata.size();
16572 
16573  MPI_Bcast(&root_n_udata_sent_to_all_proc, // Data to send and
16574  // receive
16575  1, MPI_UNSIGNED, root_processor,
16576  comm_pt->mpi_comm());
16577 
16578  // Resize the container if this is a processor that receives data
16579  if (my_rank != root_processor)
16580  {
16581  flat_packed_root_send_receive_udata.
16582  resize(root_n_udata_sent_to_all_proc);
16583  }
16584 
16585  // Send the info. from root and receive it on all processors
16586  MPI_Bcast(&flat_packed_root_send_receive_udata[0], // Info. sent
16587  // from root to
16588  // all
16589  // processors
16590  root_n_udata_sent_to_all_proc, // Number of data sent
16591  // from root to each
16592  // procesor
16593  MPI_UNSIGNED,
16594  root_processor, // The processor that sends all the info.
16595  comm_pt->mpi_comm());
16596 
16597  // Counter to extract the info.
16598  counter = 0;
16599  // Read the number of global nodes
16600  const unsigned n_global_nodes =
16601  flat_packed_root_send_receive_udata[counter++];
16602  // Store the global names of the nodes
16603  // global_node_name[x][ ][ ] Global node number
16604  // global_node_name[ ][x][ ] Global node names
16605  // global_node_name[ ][ ][x] Global node info.
16606  //Vector<Vector<Vector<unsigned> > > global_node_names(n_global_nodes);
16607  // Resize the input vector
16608  global_node_names.resize(n_global_nodes);
16609  // Now loop until all global nodes info. has been read
16610  unsigned n_read_global_nodes = 0;
16611  while (n_read_global_nodes < n_global_nodes)
16612  {
16613  // Read the number of names for the current global node
16614  const unsigned n_names_global_inode =
16615  flat_packed_root_send_receive_udata[counter++];
16616  // Counter for the global node
16617  const unsigned i = n_read_global_nodes;
16618  // Resize the container
16619  global_node_names[i].resize(n_names_global_inode);
16620  // loop over the names of the global inode
16621  for (unsigned j = 0; j < n_names_global_inode; j++)
16622  {
16623  // Resize the container
16624  global_node_names[i][j].resize(n_info_per_node_name);
16625  // loop over the info. of the j-th node name of the i-th
16626  // global node
16627  for (unsigned k = 0; k < n_info_per_node_name; k++)
16628  {
16629  // Read the k-th node info. from the j-th node name of
16630  // the i-th global node
16631  global_node_names[i][j][k] =
16632  flat_packed_root_send_receive_udata[counter++];
16633 
16634  } // for (k < n_info_per_node_name)
16635 
16636  // Create the map from the node name to the global node
16637  // index
16638  Vector<unsigned> node_name(n_info_per_node_name-1);
16639  node_name[0] = global_node_names[i][j][0];
16640  node_name[1] = global_node_names[i][j][1];
16641  node_name[2] = global_node_names[i][j][2];
16642  node_name[3] = global_node_names[i][j][3];
16643  // Do not add the local index since it will not longer be
16644  // used. Additionally, we will not know the local node
16645  // index outside this method
16646  // node_name[4] = global_node_names[i][j][4];
16647  node_name_to_global_index[node_name] = i;
16648 
16649  } // for (j < n_names_global_inode)
16650 
16651  // Increase the counter for read global nodes
16652  n_read_global_nodes++;
16653 
16654  } // while (n_read_global_nodes < n_global_nodes)
16655 
16656 #ifdef PARANOID
16657  // Check we have read all the info.
16658  if (counter != root_n_udata_sent_to_all_proc)
16659  {
16660  std::ostringstream error_stream;
16661  error_stream
16662  <<"The info. received from root regarding the global names of "
16663  <<"the nodes\nwas not completely read.\n"
16664  << "The number of data sent/received from root is: ("
16665  <<root_n_udata_sent_to_all_proc<<")\n"
16666  <<"The number of data read from the received info. is: ("
16667  <<counter<<")\n\n";
16668  throw OomphLibError(error_stream.str(),
16669  OOMPH_CURRENT_FUNCTION,
16670  OOMPH_EXCEPTION_LOCATION);
16671  } // if (counter != root_n_udata_sent_to_all_proc)
16672 #endif
16673 
16674  // ---------------------------------------------------------------
16675  // END: Send the info. back to all processors, unpackage the info.
16676  // and create the map from node name to global node index
16677  // ---------------------------------------------------------------
16678 
16679  // ---------------------------------------------------------------
16680  // BEGIN: Add the info. from the global node names into the
16681  // info. of the local node names. We do this because the
16682  // local node names have pointers to the nodes.
16683  // Additionally, create a map from the node name to the
16684  // index of its global node
16685  // ---------------------------------------------------------------
16686 
16687  // Resize the global shared node pointers container
16688  global_shared_node_pt.resize(n_global_nodes, 0);
16689 
16690  // loop over the number of global nodes
16691  for (unsigned i = 0; i < n_global_nodes; i++)
16692  {
16693  // Flag to indicate that the iglobal node is part of the nodes
16694  // on the current processor
16695  bool is_this_a_local_node_name = false;
16696  unsigned local_node_number;
16697  // Get the number of names of the i-th global node
16698  const unsigned n_names_global_inode = global_node_names[i].size();
16699  // loop over the names of the i-th global node
16700  for (unsigned j = 0; j < n_names_global_inode; j++)
16701  {
16702  // Get the node name info.
16703  const unsigned iproc = global_node_names[i][j][0];
16704  local_node_number = global_node_names[i][j][4];
16705 
16706  // Check if this node name lives on this processor
16707  if (my_rank == iproc)
16708  {
16709  // The node is part of the local node names
16710  is_this_a_local_node_name = true;
16711  // Break
16712  break;
16713  } // if (my_rank == iproc)
16714 
16715  } // for (j < n_names_global_inode)
16716 
16717  // If the node is part of the local nodes then add the
16718  // additional names of the node in the local container
16719  if (is_this_a_local_node_name)
16720  {
16721 #ifdef PARANOID
16722  // Check that the global node include at least all the names
16723  // of the node on this processor
16724  const unsigned n_names_local_node =
16725  local_node_names[local_node_number].size();
16726  unsigned n_names_found_on_global_name_node = 0;
16727 #endif
16728 
16729  // Add the pointer of the node into the global shared node
16730  // pointers container
16731  global_shared_node_pt[i] = local_node_pt[local_node_number];
16732 
16733  // Add all the global names of the node onto the local node
16734  // names
16735 
16736  // loop again over the names of the i-th global node
16737  for (unsigned j = 0; j < n_names_global_inode; j++)
16738  {
16739  // Get the node name info.
16740  const unsigned iproc = global_node_names[i][j][0];
16741 
16742  // Is this a node name on this processor?
16743  if (iproc != my_rank)
16744  {
16745  // Add the name
16746  local_node_names[local_node_number].
16747  push_back(global_node_names[i][j]);
16748  }
16749 #ifdef PARANOID
16750  else
16751  {
16752  const unsigned jproc = global_node_names[i][j][1];
16753  const unsigned ishd_bnd = global_node_names[i][j][2];
16754  const unsigned idx = global_node_names[i][j][3];
16755  const unsigned n_local_node = global_node_names[i][j][4];
16756  // loop over the names of the local node
16757  for (unsigned k = 0; k < n_names_local_node; k++)
16758  {
16759  if ((local_node_names[local_node_number][k][0] == iproc) &&
16760  (local_node_names[local_node_number][k][1] == jproc) &&
16761  (local_node_names[local_node_number][k][2] == ishd_bnd) &&
16762  (local_node_names[local_node_number][k][3] == idx) &&
16763  (local_node_names[local_node_number][k][4] == n_local_node))
16764  {
16765  // Increase the number of local nodes found on the
16766  // global nodes
16767  n_names_found_on_global_name_node++;
16768  } // found global node on local nodes
16769 
16770  } // for (k < n_names_local_node)
16771 
16772  } // if (iproc != my_rank)
16773 #endif
16774 
16775  } // for (j < n_names_global_inode)
16776 
16777 #ifdef PARANOID
16778  // The number of local nodes names must be the same as the the
16779  // number of global nodes names associated with this processor
16780  // (my_rank, that start with iproc = my_rank)
16781  if (n_names_local_node != n_names_found_on_global_name_node)
16782  {
16783  std::ostringstream error_stream;
16784  error_stream
16785  <<"The local node names corresponding to the local "
16786  <<"node ("<< local_node_number << ") were\n"
16787  <<"not found on the global node names.\n\n"
16788  << "These are the names of the local node\n"
16789  << "Name k: iproc, jproc, ishd_bnd, idx. #node\n";
16790  for (unsigned k = 0; k < n_names_local_node; k++)
16791  {
16792  error_stream<<"Name("<<k<<"): "
16793  <<local_node_names[local_node_number][k][0]
16794  <<", "<<local_node_names[local_node_number][k][1]
16795  <<", "<<local_node_names[local_node_number][k][2]
16796  <<", "<<local_node_names[local_node_number][k][3]
16797  <<", "<<local_node_names[local_node_number][k][4]
16798  <<"\n";
16799  }
16800 
16801  error_stream
16802  << "\n\nThese are the names of the global node\n"
16803  << "Name k: iproc, jproc, ishd_bnd, idx. #node\n";
16804  for (unsigned k = 0; k < n_names_global_inode; k++)
16805  {
16806  error_stream<<"Name("<<k<<"): "
16807  <<global_node_names[i][k][0] <<", "
16808  <<global_node_names[i][k][1] <<", "
16809  <<global_node_names[i][k][2] <<", "
16810  <<global_node_names[i][k][3] <<", "
16811  <<global_node_names[i][k][4] <<"\n";
16812  }
16813 
16814  throw OomphLibError(error_stream.str(),
16815  OOMPH_CURRENT_FUNCTION,
16816  OOMPH_EXCEPTION_LOCATION);
16817  }
16818 #endif
16819 
16820  } // if (is_this_a_local_node_name)
16821 
16822  } // for (i < n_global_nodes)
16823 
16824  // ---------------------------------------------------------------
16825  // END: Add the info. from the global node names into the info.
16826  // of the local node names. We do this because the local
16827  // node names have pointers to the nodes
16828  // ---------------------------------------------------------------
16829 
16830  // ---------------------------------------------------------------
16831  // BEGIN: Fill the data structure other_proc_shd_bnd_node_pt with
16832  // the local nodes.
16833  // ---------------------------------------------------------------
16834 
16835  // Loop over the local nodes and fill the
16836  // other_proc_shd_bnd_node_pt container with the corresponding
16837  // info. NOTE: We are using the old size of the local node names,
16838  // before adding the names of the global nodes so we only loop
16839  // over the local nodes and not global.
16840 
16841  // Compute the local shared boudary id
16842  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
16843 
16844  // loop over the local nodes names
16845  for (unsigned i = 0 ; i < n_local_nodes; i++)
16846  {
16847  // Get the number of names for the i-th local node
16848  const unsigned n_names = local_node_names[i].size();
16849  // Get a pointer to the first name of the node found on this
16850  // processor (this ensures that the node lives on this
16851  // processor)
16852  Node* node_pt = local_node_pt[i];
16853  // loop over the names of the i-th local node and add an entry
16854  // to the other_proc_shd_bnd_node_pt structure
16855  for (unsigned j = 0; j < n_names; j++)
16856  {
16857  // Get the node name info.
16858  const unsigned iproc = local_node_names[i][j][0];
16859  const unsigned jproc = local_node_names[i][j][1];
16860  const unsigned ishd_bnd =
16861  local_node_names[i][j][2] - initial_shd_bnd_id;
16862  const unsigned index = local_node_names[i][j][3];
16863  // We can ignore the last entry, it was just used to compute
16864  // the global node number by the root processor
16865 
16866  // Get the smallest processor number
16867  if (iproc < jproc)
16868  {
16869  other_proc_shd_bnd_node_pt[iproc][jproc][ishd_bnd][index]=node_pt;
16870  }
16871  else
16872  {
16873  other_proc_shd_bnd_node_pt[jproc][iproc][ishd_bnd][index]=node_pt;
16874  }
16875 
16876  } // for (j < n_names)
16877 
16878  } // for (i < n_local_node_names)
16879 
16880  // ---------------------------------------------------------------
16881  // END: Fill the data structure other_proc_shd_bnd_node_pt with
16882  // the local nodes.
16883  // ---------------------------------------------------------------
16884 
16885 }
16886 
16887  //======================================================================
16888  // \short Get the original boundaries to which is associated each
16889  // shared node, and send the info. to the related processors. We
16890  // need to do this so that at the reset of halo(ed) info. stage,
16891  // the info. is updated
16892 template <class ELEMENT>
16895  Vector<Vector<Vector<unsigned> > > &global_node_names,
16896  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
16897  Vector<Node*> &global_shared_node_pt)
16898 {
16899  // Get the rank and number of processors
16900  const unsigned nproc = this->communicator_pt()->nproc();
16901  const unsigned my_rank = this->communicator_pt()->my_rank();
16902 
16903  // The number of nodes on shared boundaries
16904  const unsigned n_nodes_on_shd_bnds = global_node_names.size();
16905  // ---------------------------------------------------------
16906  // BEGIN: Get the shared nodes between each of processors
16907  // ---------------------------------------------------------
16908 
16909  // Store the nodes on shared boundaries in this processor with other
16910  // processors
16911  Vector<std::set<Node*> > node_on_shd_bnd_pt(nproc);
16912 
16913  // A map to get access to the global shared node number from the
16914  // node pointer
16915  std::map<Node*, unsigned> node_pt_to_global_shd_bnd_index;
16916 
16917  // loop over the global nodes names and get only those in this
16918  // processor
16919  for (unsigned i = 0; i < n_nodes_on_shd_bnds; i++)
16920  {
16921  // Get the number of names of the current node on shared
16922  // boundaries
16923  const unsigned n_names = global_node_names[i].size();
16924  // loop over the names
16925  for (unsigned j = 0; j < n_names; j++)
16926  {
16927  // Store the node name
16928  Vector<unsigned> node_name(4);
16929  node_name[0] = global_node_names[i][j][0];
16930  node_name[1] = global_node_names[i][j][1];
16931  node_name[2] = global_node_names[i][j][2];
16932  node_name[3] = global_node_names[i][j][3];
16933 
16934  // Check whether the node is in the current processor
16935  if (node_name[0]==my_rank)
16936  {
16937  // Check with which processor the node is shared
16938  const unsigned jproc = node_name[1];
16939 
16940 #ifdef PARANOID
16941  std::map<Vector<unsigned>, unsigned>::iterator it =
16942  node_name_to_global_index.find(node_name);
16943  if (it!=node_name_to_global_index.end())
16944  {
16945  // Check whether the global node index correspond with that
16946  // of the current global node name
16947  if (i!=(*it).second)
16948  {
16949  std::ostringstream error_message;
16950  error_message
16951  <<"The global node number "<<(*it).second
16952  <<") obtained from the current node\n"
16953  <<"name is not the same as the current node number ("
16954  <<i<<").\n\n"
16955  <<"Node name:\n"
16956  <<"iproc:"<<node_name[0]<<"\n"
16957  <<"jproc:"<<node_name[1]<<"\n"
16958  <<"shd_bnd_id:"<<node_name[2]<<"\n"
16959  <<"index:"<<node_name[3]<<"\n\n";
16960  throw OomphLibError(error_message.str(),
16961  OOMPH_CURRENT_FUNCTION,
16962  OOMPH_EXCEPTION_LOCATION);
16963  }
16964 
16965  }
16966  else
16967  {
16968  std::ostringstream error_message;
16969  error_message
16970  <<"The node name is not registerd as living in this processor.\n"
16971  <<"Node name:\n"
16972  <<"iproc:"<<node_name[0]<<"\n"
16973  <<"jproc:"<<node_name[1]<<"\n"
16974  <<"shd_bnd_id:"<<node_name[2]<<"\n"
16975  <<"index:"<<node_name[3]<<"\n\n";
16976  throw OomphLibError(error_message.str(),
16977  OOMPH_CURRENT_FUNCTION,
16978  OOMPH_EXCEPTION_LOCATION);
16979  }
16980 
16981 #endif // #ifdef PARANOID
16982 
16983  // Get the node pointer
16984  Node* node_pt = global_shared_node_pt[i];
16985 
16986 #ifdef PARANOID
16987  if (node_pt == 0)
16988  {
16989  std::ostringstream error_message;
16990  error_message
16991  <<"There is not global shared node within this\n"
16992  <<"global node number ("<<i<<"). The global shared\n"
16993  <<"node pointer is null\n\n";
16994  throw OomphLibError(error_message.str(),
16995  OOMPH_CURRENT_FUNCTION,
16996  OOMPH_EXCEPTION_LOCATION);
16997  }
16998 #endif // #ifdef PARANOID
16999 
17000  // Add the node to the nodes on shared boundaries in this
17001  // processor
17002  node_on_shd_bnd_pt[jproc].insert(node_pt);
17003 
17004  // And store the global node index
17005  node_pt_to_global_shd_bnd_index[node_pt] = i;
17006 
17007  } // if (node_name[0]==my_rank)
17008  else if (node_name[1]==my_rank)
17009  {
17010  // Check with which processor the node is shared
17011  const unsigned jproc = node_name[0];
17012 
17013 #ifdef PARANOID
17014  std::map<Vector<unsigned>, unsigned>::iterator it =
17015  node_name_to_global_index.find(node_name);
17016  if (it!=node_name_to_global_index.end())
17017  {
17018  // Check whether the global node index correspond with that
17019  // of the current global node name
17020  if (i!=(*it).second)
17021  {
17022  std::ostringstream error_message;
17023  error_message
17024  <<"The global node number "<<(*it).second
17025  <<") obtained from the current node\n"
17026  <<"name is not the same as the current node number ("
17027  <<i<<").\n\n"
17028  <<"Node name:\n"
17029  <<"iproc:"<<node_name[0]<<"\n"
17030  <<"jproc:"<<node_name[1]<<"\n"
17031  <<"shd_bnd_id:"<<node_name[2]<<"\n"
17032  <<"index:"<<node_name[3]<<"\n\n";
17033  throw OomphLibError(error_message.str(),
17034  OOMPH_CURRENT_FUNCTION,
17035  OOMPH_EXCEPTION_LOCATION);
17036  }
17037 
17038  }
17039  else
17040  {
17041  std::ostringstream error_message;
17042  error_message
17043  <<"The node name is not registerd as living in this processor.\n"
17044  <<"Node name:\n"
17045  <<"iproc:"<<node_name[0]<<"\n"
17046  <<"jproc:"<<node_name[1]<<"\n"
17047  <<"shd_bnd_id:"<<node_name[2]<<"\n"
17048  <<"index:"<<node_name[3]<<"\n\n";
17049  throw OomphLibError(error_message.str(),
17050  OOMPH_CURRENT_FUNCTION,
17051  OOMPH_EXCEPTION_LOCATION);
17052  }
17053 
17054 #endif // #ifdef PARANOID
17055 
17056  // Get the node pointer
17057  Node* node_pt = global_shared_node_pt[i];
17058 
17059 #ifdef PARANOID
17060  if (node_pt == 0)
17061  {
17062  std::ostringstream error_message;
17063  error_message
17064  <<"There is not global shared node within this\n"
17065  <<"global node number ("<<i<<"). The global shared\n"
17066  <<"node pointer is null\n\n";
17067  throw OomphLibError(error_message.str(),
17068  OOMPH_CURRENT_FUNCTION,
17069  OOMPH_EXCEPTION_LOCATION);
17070  }
17071 #endif // #ifdef PARANOID
17072 
17073  // Add the node to the nodes on shared boundaries in this
17074  // processor
17075  node_on_shd_bnd_pt[jproc].insert(node_pt);
17076 
17077  // And store the global node index
17078  node_pt_to_global_shd_bnd_index[node_pt] = i;
17079 
17080  }
17081 
17082  } // for (j < n_names)
17083 
17084  } // for (i < n_nodes_on_shd_bnds)
17085 
17086  // ---------------------------------------------------------
17087  // END: Get the shared nodes between each of processors
17088  // ---------------------------------------------------------
17089 
17090  // ---------------------------------------------------------
17091  // BEGIN: Get the original boundaries associated to each
17092  // node on a shared boundary
17093  // ---------------------------------------------------------
17094 
17095  // Store the global shared node number
17096  Vector<Vector<unsigned> > global_node_on_shared_bound(nproc);
17097  // Store the boundaries associated with the global shared node
17098  // number
17099  Vector<Vector<Vector<unsigned> > > global_node_original_boundaries(nproc);
17100  // Store the zeta boundary coordinate of the nodes on original
17101  // boundaries
17102  Vector<Vector<Vector<double> > > global_node_zeta_coordinate(nproc);
17103 
17104  // loop over the processors
17105  for (unsigned iproc = 0; iproc < nproc; iproc++)
17106  {
17107  // Get the nodes added to be shared with the iproc processor
17108  std::set<Node*> nodes_shared_pt = node_on_shd_bnd_pt[iproc];
17109 
17110  // loop over the nodes
17111  for (std::set<Node*>::iterator it = nodes_shared_pt.begin();
17112  it!=nodes_shared_pt.end(); it++)
17113  {
17114  // Get the node
17115  Node* node_pt = (*it);
17116  // Store the boundaries on which it is stored
17117  Vector<unsigned> on_original_boundaries;
17118  // For each boundary get the corresponding z value of the node
17119  // on the boundary
17120  Vector<double> zeta_coordinate;
17121  // Get the number of boudandaries
17122  const unsigned n_bnd=this->initial_shared_boundary_id();
17123  // loop over the boundaries and register the boundaries to which
17124  // it is associated
17125  for (unsigned bb = 0; bb < n_bnd; bb++)
17126  {
17127  // Is the node on original boundary bb?
17128  if (node_pt->is_on_boundary(bb))
17129  {
17130  // Then save it as being on boundary bb
17131  on_original_boundaries.push_back(bb);
17132  // Get the boundary coordinate
17133  Vector<double> zeta(1);
17134  node_pt->get_coordinates_on_boundary(bb, zeta);
17135  // Save the boundary coordinate
17136  zeta_coordinate.push_back(zeta[0]);
17137  }
17138 
17139  } // for (bb < n_bnd)
17140 
17141  // Is the node on an original boundary
17142  if (on_original_boundaries.size()>0)
17143  {
17144  // Get the global shared node number
17145  std::map<Node*,unsigned>::iterator it_index =
17146  node_pt_to_global_shd_bnd_index.find(node_pt);
17147 #ifdef PARANOID
17148  if (it_index==node_pt_to_global_shd_bnd_index.end())
17149  {
17150  std::ostringstream error_message;
17151  error_message
17152  <<"We could not find the global shared node index associated\n"
17153  <<"with the node pointer with vertices coordinates:\n"
17154  <<"("<<node_pt->x(0)<<", "<<node_pt->x(1)<<")\n\n";
17155  throw OomphLibError(error_message.str(),
17156  OOMPH_CURRENT_FUNCTION,
17157  OOMPH_EXCEPTION_LOCATION);
17158  }
17159 #endif
17160  // The global shared node index
17161  const unsigned global_shared_node_number = (*it_index).second;
17162  // Store the global shared node number
17163  global_node_on_shared_bound[iproc].push_back(global_shared_node_number);
17164  // And store the original boundaries to which it is associated
17165  global_node_original_boundaries[iproc].
17166  push_back(on_original_boundaries);
17167  // and the corresponding zeta coordinate
17168  global_node_zeta_coordinate[iproc].push_back(zeta_coordinate);
17169  }
17170 
17171  } // loop over nodes on shared boundaries with iproc
17172 
17173  } // for (iproc < nproc)
17174 
17175  // ---------------------------------------------------------
17176  // END: Get the original boundaries associated to each
17177  // node on a shared boundary
17178  // ---------------------------------------------------------
17179 
17180  // ---------------------------------------------------------
17181  // BEGIN: Send the info. to the corresponding processors,
17182  // package the info, send it and receive it in the
17183  // corresponding processor, unpackage and set the
17184  // boundaries associated with the received nodes
17185  // ---------------------------------------------------------
17186 
17187  // Get the communicator of the mesh
17188  OomphCommunicator* comm_pt = this->communicator_pt();
17189 
17190  // Set MPI info
17191  MPI_Status status;
17192  MPI_Request request;
17193 
17194  // loop over the processors
17195  for (unsigned iproc = 0; iproc < nproc; iproc++)
17196  {
17197  // The number of nodes shared between the pair of processors
17198  const unsigned n_shd_nodes_my_rank_iproc =
17199  node_on_shd_bnd_pt[iproc].size();
17200 
17201  // Are there shared nodes between these pair of processors
17202  // (my_rank, iproc)? Also ensure not to send info. within myself
17203  if (n_shd_nodes_my_rank_iproc > 0 && iproc != my_rank)
17204  {
17205  // The flat package to send the info, to the iproc processor
17206  Vector<unsigned> flat_package_unsigned_send;
17207  // The very first entry is the number of nodes shared by the
17208  // pair of processors (my_rank, iproc)
17209  flat_package_unsigned_send.push_back(n_shd_nodes_my_rank_iproc);
17210 
17211  // Get the number of shared nodes on original boundaries
17212  const unsigned n_global_shared_node_on_original_boundary =
17213  global_node_on_shared_bound[iproc].size();
17214 
17215  // The second data is the number of shared nodes on original
17216  // boundaries
17217  flat_package_unsigned_send.
17218  push_back(n_global_shared_node_on_original_boundary);
17219 
17220  // ... also send the zeta coordinates associated with the
17221  // original boundaries
17222  Vector<double> flat_package_double_send;
17223 
17224  // loop over the nodes shared between this pair of processors
17225  for (unsigned i = 0; i < n_global_shared_node_on_original_boundary; i++)
17226  {
17227  // Get the global shared node index
17228  const unsigned global_shared_node_index =
17229  global_node_on_shared_bound[iproc][i];
17230 
17231  // Put in the package the shared node index of the current
17232  // node
17233  flat_package_unsigned_send.push_back(global_shared_node_index);
17234 
17235  // Get the original boundaries to which the node is associated
17236  Vector<unsigned> on_original_boundaries =
17237  global_node_original_boundaries[iproc][i];
17238 
17239  // Get the associated zeta boundary coordinates
17240  Vector<double> zeta_coordinate =
17241  global_node_zeta_coordinate[iproc][i];
17242 
17243  // Get the number of original boundaries to which the node is
17244  // associated
17245  const unsigned n_original_boundaries =
17246  on_original_boundaries.size();
17247 
17248  // Put in the package the number of original boundaries the
17249  // node is associated
17250  flat_package_unsigned_send.push_back(n_original_boundaries);
17251 
17252  // loop over the original boundaries ids and include them in
17253  // the package
17254  for (unsigned j = 0; j < n_original_boundaries; j++)
17255  {
17256  // Put in the package each of the original boundaries to
17257  // which it is associated
17258  flat_package_unsigned_send.push_back(on_original_boundaries[j]);
17259  // The zeta coordinate on the boundary
17260  flat_package_double_send.push_back(zeta_coordinate[j]);
17261  } // for (j < n_original_boundaries)
17262 
17263  } // for (i < n_global_shared_node_on_original_boundary)
17264 
17265  // Send data UNSIGNED -----------------------------------------
17266  // Get the size of the package to communicate to the iproc
17267  // processor
17268  const unsigned n_udata_send = flat_package_unsigned_send.size();
17269  int n_udata_send_int = n_udata_send;
17270 
17271  // Send/receive data to/from iproc processor
17272  MPI_Isend(&n_udata_send_int,1,MPI_UNSIGNED,
17273  iproc,1,comm_pt->mpi_comm(), &request);
17274 
17275  int n_udata_received_int = 0;
17276  MPI_Recv(&n_udata_received_int,1,MPI_UNSIGNED,
17277  iproc,1,comm_pt->mpi_comm(),&status);
17278  MPI_Wait(&request,MPI_STATUS_IGNORE);
17279 
17280  if (n_udata_send!=0)
17281  {
17282  MPI_Isend(&flat_package_unsigned_send[0],
17283  n_udata_send,MPI_UNSIGNED,
17284  iproc,2,comm_pt->mpi_comm(),&request);
17285  }
17286 
17287  const unsigned n_udata_received =
17288  static_cast<unsigned>(n_udata_received_int);
17289 
17290  // Where to receive the data from the iproc processor
17291  Vector<unsigned> flat_package_unsigned_receive(n_udata_received);
17292 
17293  if (n_udata_received!=0)
17294  {
17295  MPI_Recv(&flat_package_unsigned_receive[0],
17296  n_udata_received,MPI_UNSIGNED,
17297  iproc,2,comm_pt->mpi_comm(),&status);
17298  }
17299 
17300  if (n_udata_send!=0)
17301  {
17302  MPI_Wait(&request,MPI_STATUS_IGNORE);
17303  }
17304 
17305  // Send data DOUBLE -----------------------------------------
17306  // Get the size of the package to communicate to the iproc
17307  // processor
17308  const unsigned n_ddata_send = flat_package_double_send.size();
17309  int n_ddata_send_int = n_ddata_send;
17310 
17311  // Send/receive data to/from iproc processor
17312  MPI_Isend(&n_ddata_send_int,1,MPI_UNSIGNED,
17313  iproc,1,comm_pt->mpi_comm(), &request);
17314 
17315  int n_ddata_received_int = 0;
17316  MPI_Recv(&n_ddata_received_int,1,MPI_UNSIGNED,
17317  iproc,1,comm_pt->mpi_comm(),&status);
17318  MPI_Wait(&request,MPI_STATUS_IGNORE);
17319 
17320  if (n_ddata_send!=0)
17321  {
17322  MPI_Isend(&flat_package_double_send[0],
17323  n_ddata_send,MPI_DOUBLE,
17324  iproc,2,comm_pt->mpi_comm(),&request);
17325  }
17326 
17327  const unsigned n_ddata_received =
17328  static_cast<unsigned>(n_ddata_received_int);
17329 
17330  // Where to receive the data from the iproc processor
17331  Vector<double> flat_package_double_receive(n_ddata_received);
17332 
17333  if (n_ddata_received!=0)
17334  {
17335  MPI_Recv(&flat_package_double_receive[0],
17336  n_ddata_received,MPI_DOUBLE,
17337  iproc,2,comm_pt->mpi_comm(),&status);
17338  }
17339 
17340  if (n_ddata_send!=0)
17341  {
17342  MPI_Wait(&request,MPI_STATUS_IGNORE);
17343  }
17344 
17345  // Unpackage -------------------------------------------------
17346  // ... and associate the nodes to the corresponding original
17347  // boundaries
17348 
17349  // The number of nodes to be received
17350  unsigned n_shared_nodes_received = flat_package_unsigned_receive[0];
17351 
17352  // Increase and decrease the number of received shared nodes to
17353  // avoid the warning when compiling without PARANOID
17354  n_shared_nodes_received++;
17355  n_shared_nodes_received--;
17356 
17357 #ifdef PARANOID
17358  if (n_shd_nodes_my_rank_iproc != n_shared_nodes_received)
17359  {
17360  std::ostringstream error_message;
17361  error_message
17362  <<"The number of shared nodes between the pair of processors is\n"
17363  <<"not the same\n"
17364  <<"N.shared nodes proc ("<<my_rank<<") with proc ("<<iproc<<"): ("
17365  <<n_shd_nodes_my_rank_iproc<<"\n"
17366  <<"N.shared nodes proc ("<<iproc<<") with proc ("<<my_rank<<"): ("
17367  <<n_shared_nodes_received<<"\n\n"
17368  <<"You should have got the same error in proc: ("<<iproc<<")\n\n";
17369  throw OomphLibError(error_message.str(),
17370  OOMPH_CURRENT_FUNCTION,
17371  OOMPH_EXCEPTION_LOCATION);
17372  } // if (n_shd_nodes_my_rank_iproc != n_shared_nodes_received)
17373 #endif
17374 
17375  // Skip the number of nodes on shared boundaries on original
17376  // boundaries received (that is why next lines are commented)
17377 
17378  // The number of nodes on shared boundaries on original
17379  // boundaries
17380  //const unsigned n_shared_nodes_on_original_boundaries_received =
17381  // flat_package_unsigned_receive[1];
17382 
17383  // loop over the received info.
17384  unsigned current_index_data = 2;
17385  unsigned current_index_ddata = 0;
17386  while(current_index_data < n_udata_received)
17387  {
17388  // The global shared node number
17389  const unsigned global_shared_node_index =
17390  flat_package_unsigned_receive[current_index_data++];
17391 
17392  // The pointer to the node
17393  Node* node_pt = 0;
17394 
17395  // The number of original boundaries the node is associated
17396  // with
17397  const unsigned n_original_boundaries =
17398  flat_package_unsigned_receive[current_index_data++];
17399 
17400  // Get the node pointer
17401  node_pt = global_shared_node_pt[global_shared_node_index];
17402 #ifdef PARANOID
17403  if (node_pt == 0)
17404  {
17405  std::ostringstream error_message;
17406  error_message
17407  <<"The global shared node ("<<global_shared_node_index<<") "
17408  <<"could not be found in this processor!!!\n"
17409  <<"However, it was found in processor ("<<iproc<<"). The "
17410  <<"data may be no synchronised,\ntherefore "
17411  <<"we may be looking for a global shared node number that "
17412  <<"do not\ncorrespond with the one that was sent by "
17413  <<"processor ("<<iproc<<")\n\n";
17414  throw OomphLibError(error_message.str(),
17415  OOMPH_CURRENT_FUNCTION,
17416  OOMPH_EXCEPTION_LOCATION);
17417  }
17418 #endif // #ifdef PARANOID
17419 
17420  // loop over the number of original boundaries and associate
17421  // the node to each of those boundaries
17422  for (unsigned i = 0; i < n_original_boundaries; i++)
17423  {
17424  // Get the original boundary to which the node is associated
17425  // with
17426  const unsigned original_bound_id =
17427  flat_package_unsigned_receive[current_index_data++];
17428 
17429  // Associate the node with the boundary
17430  this->add_boundary_node(original_bound_id, node_pt);
17431 
17432  // Get the zeta boundary coordinate
17433  Vector<double> zeta(1);
17434  zeta[0] = flat_package_double_receive[current_index_ddata++];
17435  node_pt->set_coordinates_on_boundary(original_bound_id, zeta);
17436  }
17437 
17438  } // while(current_data < n_data_received)
17439 
17440  } // if ((node_on_shd_bnd_pt(iproc) > 0) && iproc!=my_rank)
17441 
17442  } // for (iproc < nproc)
17443 
17444  // ---------------------------------------------------------
17445  // END: Send the info. to the corresponding processors,
17446  // package the info, send it and receive it in the
17447  // corresponding processor, unpackage and set the
17448  // boundaries associated with the received nodes
17449  // ---------------------------------------------------------
17450 
17451 }
17452 
17453  //======================================================================
17454  // \short In charge of creating additional halo(ed) elements on those
17455  // processors that have no shared boundaries in common but have
17456  // shared nodes
17457  // ======================================================================
17458 template <class ELEMENT>
17460  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
17461  &other_proc_shd_bnd_node_pt,
17462  Vector<Vector<Node *> > &iproc_currently_created_nodes_pt,
17463  Vector<Vector<Vector<unsigned> > > &global_node_names,
17464  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
17465  Vector<Node*> &global_shared_node_pt)
17466  {
17467  // Get the rank and number of processors
17468  const unsigned nproc = this->communicator_pt()->nproc();
17469  const unsigned my_rank = this->communicator_pt()->my_rank();
17470 
17471  // ---------------------------------------------------------------
17472  // BEGIN: Create a map to check whether a node is on the global
17473  // shared nodes. Also set a map to obtain the global
17474  // shared node index (this index is the same as the global
17475  // node name)
17476  // ---------------------------------------------------------------
17477  std::map<Node*, bool> is_global_shared_node;
17478  std::map<Node*, unsigned> global_shared_node_index;
17479 
17480  // Get the number of global shared nodes
17481  const unsigned n_global_shared_nodes = global_shared_node_pt.size();
17482  // loop over the global shared nodes
17483  for (unsigned i = 0; i < n_global_shared_nodes; i++)
17484  {
17485  // Get the node
17486  Node* node_pt = global_shared_node_pt[i];
17487  // Indicate this is a shared global node
17488  is_global_shared_node[node_pt] = true;
17489  // Set the map to obtain the index of the global shared node
17490  global_shared_node_index[node_pt] = i;
17491 
17492  } // for (i < n_global_shared_nodes)
17493 
17494  // ---------------------------------------------------------------
17495  // END: Create a map to check whether a node is on the global
17496  // shared nodes. Also set a map to obtain the global
17497  // shared node index (this index is the same as the global
17498  // node name)
17499  // ---------------------------------------------------------------
17500 
17501  // ---------------------------------------------------------------
17502  // BEGIN: Loop over the haloed elements and check whether the nodes
17503  // on the haloed elements are part of the global shared
17504  // nodes. If that is the case then check whether the
17505  // element should be sent to the processors with which the
17506  // node is shared
17507  // ---------------------------------------------------------------
17508 
17509  // Elements that may be sent to other processors
17510  Vector<std::set<GeneralisedElement*> > additional_elements_pt(nproc);
17511 
17512  // loop over the processors
17513  for (unsigned iproc = 0; iproc < nproc; iproc++)
17514  {
17515  if (iproc!=my_rank)
17516  {
17517  // Get the haloed element with iproc
17518  Vector<GeneralisedElement*> haloed_ele_pt =
17519  this->root_haloed_element_pt(iproc);
17520 
17521  // Get the number of haloed elements
17522  const unsigned n_haloed_ele =
17523  this->nroot_haloed_element(iproc);
17524 
17525  // loop over the haloed elements with iproc
17526  for (unsigned ihd = 0; ihd < n_haloed_ele; ihd++)
17527  {
17528  // A pointer to the generalised element
17529  GeneralisedElement* gele_pt = haloed_ele_pt[ihd];
17530  // Get the finite element representation of the element
17531  FiniteElement* ele_pt = dynamic_cast<FiniteElement*>(gele_pt);
17532  // Get the number of nodes
17533  const unsigned n_nodes = ele_pt->nnode();
17534  // loop over the nodes of the element
17535  for (unsigned n = 0; n < n_nodes; n++)
17536  {
17537  // Get the node
17538  Node* node_pt = ele_pt->node_pt(n);
17539  // Is the node a global shared node?
17540  if (is_global_shared_node[node_pt])
17541  {
17542  // Get the index of the global shared node
17543  const unsigned global_index = global_shared_node_index[node_pt];
17544  // Get the global names of the node
17545  Vector<Vector<unsigned> > iglobal_names =
17546  global_node_names[global_index];
17547 
17548  // Get the number of names
17549  const unsigned n_names = iglobal_names.size();
17550  // loop over the names and check which processors share
17551  // this node (the processors to which the element may be
17552  // sent
17553  for (unsigned j = 0; j < n_names; j++)
17554  {
17555  // Get the processors to which the element should be
17556  // sent
17557  const unsigned proc1 = iglobal_names[j][0];
17558  const unsigned proc2 = iglobal_names[j][1];
17559  // Add the element to the set of additional elements to
17560  // sent from proc1 to proc2
17561  additional_elements_pt[proc1].insert(gele_pt);
17562  additional_elements_pt[proc2].insert(gele_pt);
17563 
17564  } // for (j < n_names)
17565 
17566  } // if (is_global_shared_node[node_pt])
17567 
17568  } // for (n < n_nodes)
17569 
17570  } // for (ihd < n_haloed_ele)
17571 
17572  } // if (iproc!=my_rank)
17573 
17574  } // for (iproc < nproc)
17575 
17576  // ---------------------------------------------------------------
17577  // Now check whether the element should really be sent to the
17578  // indicated processors
17579 
17580  // The elements from this (my_rank) processor that will be sent to
17581  // other processors
17582  Vector<Vector<FiniteElement*> > send_haloed_ele_pt(nproc);
17583 
17584  // loop over the processors
17585  for (unsigned iproc = 0; iproc < nproc; iproc++)
17586  {
17587  if (iproc!=my_rank)
17588  {
17589  // Get the set of element that may be sent to the iproc
17590  // processor
17591  std::set<GeneralisedElement*> iproc_ele_pt =
17592  additional_elements_pt[iproc];
17593  // loop over the element that may be sent to the iproc
17594  // processor
17595  for (std::set<GeneralisedElement*>::iterator it =
17596  iproc_ele_pt.begin(); it!=iproc_ele_pt.end(); it++)
17597  {
17598  // Get a pointer to the element
17599  GeneralisedElement* gele_pt = (*it);
17600 
17601  // Get the haloed element with iproc
17602  Vector<GeneralisedElement*> haloed_ele_pt =
17603  this->root_haloed_element_pt(iproc);
17604 
17605  // Get the number of haloed elements
17606  const unsigned n_haloed_ele = this->nroot_haloed_element(iproc);
17607 
17608  // Flag to indicate whether the element has been already sent
17609  // to the iproc processor
17610  bool send_ele_to_iproc_processor = true;
17611  // loop over the haloed elements with iproc and check whether
17612  // the element has been already sent to iproc (if it is
17613  // already a haloed element with iproc then it has been
17614  // already sent)
17615  for (unsigned ihd = 0; ihd < n_haloed_ele; ihd++)
17616  {
17617  // A pointer to the generalised element
17618  GeneralisedElement* ghd_ele_pt = haloed_ele_pt[ihd];
17619  if (gele_pt == ghd_ele_pt)
17620  {
17621  // Mark the element as not required to be sent
17622  send_ele_to_iproc_processor = false;
17623  // Break the loop that searchs for the element on the
17624  // haloed elements with iproc
17625  break;
17626  }
17627 
17628  } // for (ihd < n_haloed_ele)
17629 
17630  // Do we need to sent the element?
17631  if (send_ele_to_iproc_processor)
17632  {
17633  // Get the finite element representation of the element
17634  FiniteElement* ele_pt = dynamic_cast<FiniteElement*>(gele_pt);
17635  // Add the element to those that will be sent to the iproc
17636  // processor
17637  send_haloed_ele_pt[iproc].push_back(ele_pt);
17638  }
17639 
17640  } // loop over the elements that may be sent to the iproc
17641  // processor
17642 
17643  } // if (iproc!=my_rank)
17644 
17645  } // for (iproc < nproc)
17646 
17647  // ---------------------------------------------------------------
17648  // END: Loop over the haloed element and check whether the nodes
17649  // on the haloed elements are part of the global shared
17650  // nodes. If that is the case then check whether the element
17651  // should be sent to the processors with which the node is
17652  // shared
17653  // ---------------------------------------------------------------
17654 
17655  // ============================================================
17656  // Now send the additional elements
17657  // ============================================================
17658  // Loop over the processors to send data
17659  for (unsigned iproc = 0; iproc < nproc; iproc++)
17660  {
17661  // There are no elements to send with myself
17662  if (iproc != my_rank)
17663  {
17664  // Get the number of additional haloed elements to send
17665  const unsigned n_additional_haloed_ele =
17666  send_haloed_ele_pt[iproc].size();
17667 
17668  // Clear send and receive buffers
17669  Flat_packed_unsigneds.clear();
17670  Flat_packed_doubles.clear();
17671 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17672  Flat_packed_unsigneds_string.clear();
17673 #endif
17674 
17675  // The very first data of the flat packed is the number of
17676  // additional haloed elements, this will be the number of
17677  // additional halo elements to create on the receiver processor
17678  Flat_packed_unsigneds.push_back(n_additional_haloed_ele);
17679 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17680  std::stringstream junk;
17681  junk << "Number of haloed elements " << nhaloed_ele;
17682  Flat_packed_unsigneds_string.push_back(junk.str());
17683 #endif
17684 
17685  // Loop over the additioanl haloed elements
17686  for (unsigned e = 0; e < n_additional_haloed_ele; e++)
17687  {
17688  // Get pointer to the additional haloed element
17689  FiniteElement* ele_pt = send_haloed_ele_pt[iproc][e];
17690  const unsigned nroot_haloed_ele =
17691  this->nroot_haloed_element(iproc);
17692 
17693  // Check if the element has been already added to the
17694  // halo(ed) scheme
17695 
17696  // Get the generalised version of the element
17697  GeneralisedElement *gen_ele_pt = ele_pt;
17698  // Try to add the haloed element
17699  const unsigned haloed_ele_index =
17700  this->try_to_add_root_haloed_element_pt(iproc, gen_ele_pt);
17701 
17702  // Was the element added or only returned the index of the
17703  // element
17704  if (nroot_haloed_ele == haloed_ele_index)
17705  {
17706  Flat_packed_unsigneds.push_back(1);
17707 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17708  Flat_packed_unsigneds_string.push_back("Haloed element needs to be constructed");
17709 #endif
17710 
17711  // Get additional info. related with the haloed element
17712  get_required_elemental_information_helper(iproc, ele_pt);
17713 
17714  // Get the nodes on the element
17715  const unsigned nnodes = ele_pt->nnode();
17716  for (unsigned j = 0; j < nnodes; j++)
17717  {
17718  Node* node_pt = ele_pt->node_pt(j);
17719 
17720  // Package the info. of the nodes
17721  // The destination processor goes in the arguments
17722  add_haloed_node_helper(iproc, node_pt);
17723 
17724  } // for (j < nnodes)
17725 
17726  } // add the element and send its nodes
17727  else // The haloed element already exists
17728  {
17729  Flat_packed_unsigneds.push_back(0);
17730 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17731  Flat_packed_unsigneds_string.push_back("Haloed element already exists");
17732 #endif
17733  Flat_packed_unsigneds.push_back(haloed_ele_index);
17734 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17735  Flat_packed_unsigneds_string.push_back("Index of existing haloed element");
17736 #endif
17737  } // else (next_haloed_ele == external_haloed_ele_index)
17738 
17739  } // for (e < n_additional_haloed_ele)
17740 
17741  // Send and received the additional haloed elements (all
17742  // processors send and receive)
17743 
17744  // The processor to which send the elements
17745  int send_proc = static_cast<int>(iproc);
17746  // The processor from which receive the elements
17747  int recv_proc = static_cast<int>(iproc);
17748  send_and_receive_elements_nodes_info(send_proc, recv_proc);
17749 
17750  // Reset the counters
17751  Counter_for_flat_packed_doubles=0;
17752  Counter_for_flat_packed_unsigneds=0;
17753 
17754  // Get the number of additional halo element to be created
17755  const unsigned n_additional_halo_ele =
17756  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
17757 
17758 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17759  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
17760  << " Number of elements need to be constructed "
17761  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
17762  << std::endl;
17763 #endif
17764 
17765  // Create the additional halo elements
17766  for (unsigned e = 0; e < n_additional_halo_ele; e++)
17767  {
17768  // Create halo element from received info. of "iproc"
17769  // processor on the current processor
17770  create_halo_element(iproc,
17771  iproc_currently_created_nodes_pt[iproc],
17772  other_proc_shd_bnd_node_pt,
17773  global_node_names,
17774  node_name_to_global_index,
17775  global_shared_node_pt);
17776 
17777  } // for (e < n_additional_halo_ele)
17778 
17779  } // if (iproc != my_rank)
17780 
17781  } // for (iproc < nproc)
17782 
17783  }
17784 
17785  // *********************************************************************
17786  // Start communication functions
17787  // *********************************************************************
17788 
17789  //========start of get_required_elemental_information_helper==============
17790  /// \short Helper function to get the required elemental information from
17791  /// an haloed element. This info. involves the association of the element
17792  /// to a boundary or region.
17793  //========================================================================
17794  template<class ELEMENT>
17797  FiniteElement* ele_pt)
17798  {
17799  // Check if the element is associated with the original boundaries
17800  const unsigned nbound = this->initial_shared_boundary_id();
17801 
17802  // ------------------------------------------------------------------
17803  // Stores the information regarding the boundaries associated to the
17804  // element (it that is the case)
17805  Vector<unsigned> associated_boundaries;
17806  Vector<unsigned> face_index_on_boundary;
17807 
17808  unsigned counter_face_indexes = 0;
17809 
17810  for (unsigned b = 0; b < nbound; b++)
17811  {
17812  // Get the number of elements associated to boundary i
17813  const unsigned nboundary_ele = nboundary_element(b);
17814  for (unsigned e = 0; e < nboundary_ele; e++)
17815  {
17816  if (ele_pt == this->boundary_element_pt(b,e))
17817  {
17818  // Keep track of the boundaries associated to the element
17819  associated_boundaries.push_back(b);
17820  // Get the face index
17821  face_index_on_boundary.push_back(face_index_at_boundary(b,e));
17822  counter_face_indexes++;
17823 #ifdef PARANOID
17824  if (counter_face_indexes > 2)
17825  {
17826  std::stringstream error_message;
17827  error_message
17828  << "A triangular element can not have more than two of its faces "
17829  << "on a boundary!!!\n\n";
17830  throw OomphLibError(error_message.str(),
17831  OOMPH_CURRENT_FUNCTION,
17832  OOMPH_EXCEPTION_LOCATION);
17833  }
17834 #else
17835  // Already found 2 face indexes on the same boundary?
17836  if (counter_face_indexes==2) {break;}
17837 #endif // #ifdef PARANOID
17838 
17839  } // if (ele_pt == this->boundary_element_pt(b,e))
17840 
17841  } // (e < nboundary_ele)
17842 
17843  } // (b < nbound)
17844 
17845  // If the element is associated to any boundary then package all the
17846  // relevant info
17847  const unsigned nassociated_boundaries = associated_boundaries.size();
17848  if (nassociated_boundaries > 0)
17849  {
17850  Flat_packed_unsigneds.push_back(1);
17851 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17852  Flat_packed_unsigneds_string.push_back("The element is a boundary element");
17853 #endif
17854  Flat_packed_unsigneds.push_back(nassociated_boundaries);
17855 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17856  std::stringstream junk;
17857  junk << "The elements is associated to " << nassociated_boundaries << " boundaries";
17858  Flat_packed_unsigneds_string.push_back(junk.str());
17859 #endif
17860 
17861  // Package the ids of the associated boundaries and the
17862  // corresponding face index for each boundary (if the element is a
17863  // corner element, it will have two faces associated to the
17864  // boundary)
17865  for (unsigned i = 0; i < nassociated_boundaries; i++)
17866  {
17867  unsigned b = associated_boundaries[i];
17868  Flat_packed_unsigneds.push_back(b);
17869 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17870  std::stringstream junk;
17871  junk << "Element associated to boundary " << b << " of " << nassociated_boundaries << " total associated boundaries";
17872  Flat_packed_unsigneds_string.push_back(junk.str());
17873 #endif
17874  unsigned f = face_index_on_boundary[i];
17875  Flat_packed_unsigneds.push_back(f);
17876 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17877  std::stringstream junk2;
17878  junk2 << "Face index " << f << " for associated boundary " << b;
17879  Flat_packed_unsigneds_string.push_back(junk2.str());
17880 #endif
17881  }
17882 
17883  // If the element is associated to any boundary then we should
17884  // check if the mesh has regions, if that is the case then we need
17885  // to check to which region the boundary element does belong
17886 
17887  // If the mesh has regions we should look for the element
17888  // associated to a boundary and a specified region
17889  Vector<Vector<unsigned> > associated_boundaries_and_regions;
17890  Vector<unsigned> face_index_on_boundary_and_region;
17891 
17892  // Now check for the case when we have regions in the mesh
17893  const unsigned n_regions = this->nregion();
17894  if (n_regions > 1)
17895  {
17896  // Used to count the number of faces associated with
17897  // boundary-regions
17898  unsigned counter_face_indexes_in_regions = 0;
17899  // Loop over the boundaries
17900  for (unsigned b = 0; b < nbound; b++)
17901  {
17902  // Go through each region by getting the region id
17903  for (unsigned i_reg = 0 ; i_reg < n_regions; i_reg++)
17904  {
17905  // Get thre region id associated with the (i_reg)-th region
17906  const unsigned region_id =
17907  static_cast<unsigned>(this->Region_attribute[i_reg]);
17908 
17909  // Loop over all elements associated with the current boundary
17910  // and the i_reg-th region and check if the element is part of
17911  // any region
17912  const unsigned nele_in_region =
17913  this->nboundary_element_in_region(b, region_id);
17914  for (unsigned ee = 0; ee < nele_in_region; ee++)
17915  {
17916  // Check if the boundary-region element is the same as the
17917  // element
17918  if (ele_pt ==
17919  this->boundary_element_in_region_pt(b, region_id, ee))
17920  {
17921  // Storage for the boundary and region associated to the
17922  // element
17923  Vector<unsigned> bound_and_region(2);
17924 
17925  // Keep track of the boundaries associated to the element
17926  bound_and_region[0] = b;
17927  // Keep track of the regions associated to the element
17928  bound_and_region[1] = region_id;
17929  // Add the boundaries and regions in the storage to be
17930  // sent to other processors
17931  associated_boundaries_and_regions.push_back(bound_and_region);
17932  // Get the face index and keep track of it
17933  face_index_on_boundary_and_region.push_back(
17934  this->face_index_at_boundary_in_region(b,region_id,ee));
17935 
17936  // Increase the number of faces of the element associated
17937  // to boundary-regions
17938  counter_face_indexes_in_regions++;
17939 
17940 #ifdef PARANOID
17941  if (counter_face_indexes_in_regions > 2)
17942  {
17943  std::stringstream error_message;
17944  error_message
17945  << "A triangular element can not have more than two of its\n"
17946  << "faces on a boundary!!!\n\n";
17947  throw OomphLibError(error_message.str(),
17948  OOMPH_CURRENT_FUNCTION,
17949  OOMPH_EXCEPTION_LOCATION);
17950  } // if (counter_face_indexes_in_regions > 2)
17951 #endif
17952 
17953  } // The element is a boundary-region element
17954 
17955  } // for (ee < nele_in_region)
17956 
17957  } // for (i_reg < n_regions)
17958 
17959  } // for (b < nbound)
17960 
17961  } // if (n_regions > 1)
17962 
17963  // Now package the info. to be sent to other processors
17964  const unsigned nassociated_boundaries_and_regions =
17965  associated_boundaries_and_regions.size();
17966  if (nassociated_boundaries_and_regions > 0)
17967  {
17968  Flat_packed_unsigneds.push_back(1);
17969 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17970  Flat_packed_unsigneds_string.push_back("The element is associated to boundaries and regions");
17971 #endif
17972 
17973  Flat_packed_unsigneds.push_back(nassociated_boundaries_and_regions);
17974 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17975  std::stringstream junk;
17976  junk << "The element is associated to " << nassociated_boundaries_and_regions << " boundaries-regions";
17977  Flat_packed_unsigneds_string.push_back(junk.str());
17978 #endif
17979 
17980  // Package the ids of the associated boundaries, regions and the
17981  // corresponding face index for each boundary-region (if the
17982  // element is a corner element, it will have two faces
17983  // associated to the boundary-region)
17984  for (unsigned i = 0; i < nassociated_boundaries_and_regions; i++)
17985  {
17986  const unsigned b = associated_boundaries_and_regions[i][0];
17987  Flat_packed_unsigneds.push_back(b);
17988 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17989  std::stringstream junk;
17990  junk << "Element associated to boundary " << b << " of " << nassociated_boundaries_and_regions << " total associated boundaries-regions";
17991  Flat_packed_unsigneds_string.push_back(junk.str());
17992 #endif
17993 
17994  const unsigned r = associated_boundaries_and_regions[i][1];
17995  Flat_packed_unsigneds.push_back(r);
17996 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
17997  std::stringstream junk2;
17998  junk2 << "Element associated to region " << r << " of " << nassociated_boundaries_and_regions << " total associated boundaries-regions";
17999  Flat_packed_unsigneds_string.push_back(junk2.str());
18000 #endif
18001 
18002  const unsigned f = face_index_on_boundary_and_region[i];
18003  Flat_packed_unsigneds.push_back(f);
18004 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18005  std::stringstream junk3;
18006  junk3 << "Face index " << f << " for associated boundary-region (" << b << "-" << r << ")";
18007  Flat_packed_unsigneds_string.push_back(junk3.str());
18008 #endif
18009  } // for (i < nassociated_boundaries_and_regions)
18010  } // if (nassociated_boundaries_and_regions > 0)
18011  else
18012  {
18013  Flat_packed_unsigneds.push_back(0);
18014 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18015  Flat_packed_unsigneds_string.push_back("The element is NOT associated to boundaries and regions");
18016 #endif
18017  } // else if (nassociated_boundaries_and_regions > 0)
18018 
18019  }
18020  else
18021  {
18022  Flat_packed_unsigneds.push_back(0);
18023 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18024  Flat_packed_unsigneds_string.push_back("The element is not associated to any original boundary");
18025 #endif
18026  }
18027 
18028  // ------------------------------------------------------------
18029  // Now review if the element is associated to a shared boundary
18030 
18031  // Store the shared boundaries, and therefore the face indexes
18032  // associated to the element
18033  Vector<unsigned> associated_shared_boundaries;
18034  Vector<unsigned> face_index_on_shared_boundary;
18035 
18036  // Get the shared boundaries in this processor
18037  Vector<unsigned> my_rank_shared_boundaries_ids;
18038  this->shared_boundaries_in_this_processor(my_rank_shared_boundaries_ids);
18039 
18040  // Get the number of shared boundaries
18041  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
18042  // Loop over the shared boundaries
18043  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
18044  {
18045  // Get the boundary id
18046  const unsigned sb = my_rank_shared_boundaries_ids[i];
18047 
18048  // Get the number of elements associated to shared boundary sb
18049  const unsigned nboundary_ele = this->nshared_boundary_element(sb);
18050  for (unsigned e = 0; e < nboundary_ele; e++)
18051  {
18052  if (ele_pt == this->shared_boundary_element_pt(sb,e))
18053  {
18054  // Keep track of the boundaries associated to the element
18055  associated_shared_boundaries.push_back(sb);
18056  // Get the face index
18057  face_index_on_shared_boundary.push_back(
18058  this->face_index_at_shared_boundary(sb, e));
18059  }
18060  } // (e < nboundary_ele)
18061  } // (i < nmy_rank_shd_bnd)
18062 
18063  // If the element is associated to a shared boundary then package
18064  // all the relevant info
18065  const unsigned nassociated_shared_boundaries =
18066  associated_shared_boundaries.size();
18067  if (nassociated_shared_boundaries > 0)
18068  {
18069  Flat_packed_unsigneds.push_back(3);
18070 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18071  Flat_packed_unsigneds_string.push_back("The element is a shared boundary element");
18072 #endif
18073  Flat_packed_unsigneds.push_back(nassociated_shared_boundaries);
18074 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18075  std::stringstream junk;
18076  junk << "The elements is associated to " << nassociated_shared_boundaries << "shared boundaries";
18077  Flat_packed_unsigneds_string.push_back(junk.str());
18078 #endif
18079 
18080  // Package the ids of the associated boundaries
18081  for (unsigned i = 0; i < nassociated_shared_boundaries; i++)
18082  {
18083  const unsigned b = associated_shared_boundaries[i];
18084  Flat_packed_unsigneds.push_back(b);
18085 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18086  std::stringstream junk;
18087  junk << "Element associated to shared boundary " << b << " of " << nassociated_shared_boundaries << " total associated boundaries";
18088  Flat_packed_unsigneds_string.push_back(junk.str());
18089 #endif
18090 
18091  const unsigned f = face_index_on_shared_boundary[i];
18092  Flat_packed_unsigneds.push_back(f);
18093 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18094  std::stringstream junk2;
18095  junk2 << "Face index " << f << " for associated shared boundary " << b;
18096  Flat_packed_unsigneds_string.push_back(junk2.str());
18097 #endif
18098  }
18099  }
18100  else
18101  {
18102  Flat_packed_unsigneds.push_back(0);
18103 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18104  Flat_packed_unsigneds_string.push_back("The element is not associated to any shared boundary");
18105 #endif
18106  }
18107 
18108  }
18109 
18110  //========start of get_required_nodal_information_helper==================
18111  /// Helper function to get the required nodal information from an
18112  /// haloed node so that a fully-functional halo node (and therefore element)
18113  /// can be created on the receiving process
18114  //========================================================================
18115  template<class ELEMENT>
18118  Node* nod_pt)
18119  {
18120  unsigned my_rank = this->communicator_pt()->my_rank();
18121  const unsigned nproc = this->communicator_pt()->nproc();
18122 
18123  // Tell the halo copy of this node how many values there are
18124  // [NB this may be different for nodes within the same element, e.g.
18125  // when using Lagrange multipliers]
18126  unsigned n_val=nod_pt->nvalue();
18127  Flat_packed_unsigneds.push_back(n_val);
18128 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18129  Flat_packed_unsigneds_string.push_back("Number of values");
18130 #endif
18131 
18132  unsigned n_dim=nod_pt->ndim();
18133 
18134  // Default number of previous values to 1
18135  unsigned n_prev=1;
18136  if (this->Time_stepper_pt!=0)
18137  {
18138  // Add number of history values to n_prev
18139  n_prev=this->Time_stepper_pt->ntstorage();
18140  }
18141 
18142  // -----------------------------------------------------
18143  // Is the node on an original boundary?
18144  // Store the original boundaries where the node may be
18145  Vector<unsigned> original_boundaries;
18146  // Loop over the original boundaries of the mesh and check if live
18147  // on one of them
18148  const unsigned n_bnd = this->initial_shared_boundary_id();
18149  for (unsigned bb=0;bb<n_bnd;bb++)
18150  {
18151  // Which boundaries (could be more than one) is it on?
18152  if (nod_pt->is_on_boundary(bb))
18153  {
18154  original_boundaries.push_back(bb);
18155  }
18156 
18157  }
18158 
18159  const unsigned n_original_boundaries = original_boundaries.size();
18160  // Is the node on any original boundary?
18161  if (n_original_boundaries > 0)
18162  {
18163  // Indicate that the node is on an original boundary
18164  Flat_packed_unsigneds.push_back(2);
18165 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18166  Flat_packed_unsigneds_string.push_back("Node is on the original boundaries");
18167 #endif
18168 
18169  Flat_packed_unsigneds.push_back(n_original_boundaries);
18170 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18171  std::stringstream junk;
18172  junk << "Node is on "<< n_original_boundaries << " original boundaries";
18173  Flat_packed_unsigneds_string.push_back(junk.str());
18174 #endif
18175 
18176  // Loop over the original boundaries the node is on
18177  for (unsigned i=0;i<n_original_boundaries;i++)
18178  {
18179  Flat_packed_unsigneds.push_back(original_boundaries[i]);
18180 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18181  std::stringstream junk;
18182  junk<<"Node is on boundary "<<original_boundaries[i]<<" of "<< nb;
18183  Flat_packed_unsigneds_string.push_back(junk.str());
18184 #endif
18185  // Get the boundary coordinate of the node
18186  Vector<double> zeta(1);
18187  nod_pt->get_coordinates_on_boundary(original_boundaries[i],zeta);
18188  Flat_packed_doubles.push_back(zeta[0]);
18189  }
18190  }
18191  else
18192  {
18193  // Indicate that the node is NOT on an original boundary
18194  Flat_packed_unsigneds.push_back(0);
18195 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18196  Flat_packed_unsigneds_string.push_back("Node is on any original boundary");
18197 #endif
18198  }
18199 
18200  // -------------------------------------------------------
18201  // Is the node on shared boundaries?
18202  bool node_on_shared_boundary = false;
18203  // Loop over the shared boundaries with the iproc processors and
18204  // check if live on one of them
18205  const unsigned n_shd_bnd = this->nshared_boundaries(my_rank, iproc);
18206  for (unsigned bb=0;bb<n_shd_bnd;bb++)
18207  {
18208  // Get the boundary id
18209  unsigned i_bnd = this->shared_boundaries_ids(my_rank, iproc, bb);
18210  // Which boundaries (could be more than one) is it on?
18211  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
18212  {
18213  node_on_shared_boundary = true;
18214  break;
18215  }
18216  }
18217 
18218  // If the node live on any of the shared boundaries with the iproc
18219  // processor then just get the node number according to the
18220  // sorted_shared_boundary_node_pt() scheme and send it accross
18221  if (node_on_shared_boundary)
18222  {
18223  Flat_packed_unsigneds.push_back(1);
18224 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18225  Flat_packed_unsigneds_string.push_back("Node is on shared boundary");
18226 #endif
18227 
18228  // Store the shared boundaries where the node is on
18229  Vector<unsigned> shd_boundaries;
18230  // Loop over the shared boundaries with the iproc processor
18231  for (unsigned bb = 0; bb < n_shd_bnd; bb++)
18232  {
18233  // Get the boundary id
18234  const unsigned i_bnd =
18235  this->shared_boundaries_ids(my_rank, iproc, bb);
18236  // Which boundaries (could be more than one) is it on?
18237  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
18238  {
18239  shd_boundaries.push_back(i_bnd);
18240  }
18241  }
18242 
18243  // Get the number of shared boundaries the node is on
18244  const unsigned n_shd_bnd_is_on = shd_boundaries.size();
18245  // Send the number of shared boundaries the node is on
18246  Flat_packed_unsigneds.push_back(n_shd_bnd_is_on);
18247 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18248  std::stringstream junk;
18249  junk << "Node is on "<< n_shd_bnd_is_on << " shared boundaries";
18250  Flat_packed_unsigneds_string.push_back(junk.str());
18251 #endif
18252 
18253  // Loop over the shared boundaries to send their ids
18254  for (unsigned i=0;i<n_shd_bnd_is_on;i++)
18255  {
18256  Flat_packed_unsigneds.push_back(shd_boundaries[i]);
18257 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18258  std::stringstream junk;
18259  junk << "Node is on boundary " << shd_boundaries[i] << " of " << nb;
18260  Flat_packed_unsigneds_string.push_back(junk.str());
18261 #endif
18262  }
18263 
18264  // Given that the node is on at least one boundary get the index
18265  // of the node in one of the boundaries and send this index
18266  unsigned shared_boundary_id = shd_boundaries[0];
18267  // Get the number of nodes on the given shared boundary
18268  const unsigned n_nodes_on_shared_boundary =
18269  nsorted_shared_boundary_node(shared_boundary_id);
18270  // Store the index of the node on the shared boundary
18271  unsigned index_node_on_shared_boundary;
18272 #ifdef PARANOID
18273  // Flag to know if the node has been found
18274  bool found_index_node_on_shared_boundary = false;
18275 #endif
18276  // Loop over the nodes on the shared boundary to find the node
18277  for (unsigned i = 0; i < n_nodes_on_shared_boundary; i++)
18278  {
18279  // Get the i-th node on the shared boundary
18280  Node* shared_node_pt =
18281  sorted_shared_boundary_node_pt(shared_boundary_id, i);
18282  // Is the node we are looking for
18283  if (shared_node_pt == nod_pt)
18284  {
18285  // Store the index
18286  index_node_on_shared_boundary = i;
18287 #ifdef PARANOID
18288  // Mark as found
18289  found_index_node_on_shared_boundary = true;
18290 #endif
18291  break; // break
18292  }
18293 
18294  } // for (i < nnodes_on_shared_boundary)
18295 
18296 #ifdef PARANOID
18297  if (!found_index_node_on_shared_boundary)
18298  {
18299  std::ostringstream error_message;
18300  error_message
18301  <<"The index of the node on boundary ("
18302  <<shared_boundary_id<<") was not found.\n"
18303  <<"The node coordinates are ("<<nod_pt->x(0)<<","
18304  <<nod_pt->x(1)<<").\n";
18305  throw OomphLibError(
18306  error_message.str(),
18307  "RefineableTriangleMesh::get_required_nodal_information_helper()",
18308  OOMPH_EXCEPTION_LOCATION);
18309  }
18310 #endif
18311  // Send the index of the node on the shared boundary
18312  Flat_packed_unsigneds.push_back(index_node_on_shared_boundary);
18313 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18314  std::stringstream junk2;
18315  junk2 << "Node index on boundary "<<boundaries[0]<<" is "
18316  <<index_node_on_shared_boundary;
18317  Flat_packed_unsigneds_string.push_back(junk2.str());
18318 #endif
18319 
18320  } // if (node_on_shared_boundary)
18321  else
18322  {
18323  // The node is not on a shared boundary
18324  Flat_packed_unsigneds.push_back(0);
18325 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18326  Flat_packed_unsigneds_string.push_back("Node is not on a shared boundary");
18327 #endif
18328  }
18329 
18330  // ----------------------------------------------------------------
18331  // Is the node on any shared boundary where the receiver processor
18332  // is not involved?
18333 
18334  // Now check if the node is on a shared boundary created by the
18335  // current processor (my_rank) and other processor different that
18336  // the iproc processor. This info. will help to complete the sending
18337  // of halo(ed) information between processors
18338 
18339  // Flag to know if the node is on a shared boundary with other
18340  // processor
18341  bool node_on_shared_boundary_with_other_processors = false;
18342  // Count the number of other shared boundaries it could be on
18343  unsigned nshared_boundaries_with_other_processors_have_node = 0;
18344 
18345  // Loop over the shared boundaries of the sent processor (my_rank)
18346  // and other processors (jproc)
18347  for (unsigned jproc = 0; jproc < nproc; jproc++)
18348  {
18349  // Do not search with the iproc processor , that was done before
18350  // above because we are sending info to that processor
18351  if (jproc != iproc)
18352  {
18353  // Get the number of shared boundaries with the jproc processor
18354  const unsigned n_jshd_bnd =
18355  this->nshared_boundaries(my_rank, jproc);
18356  // Loop over the shared boundaries
18357  for (unsigned bb=0;bb<n_jshd_bnd;bb++)
18358  {
18359  // Get the boundary id
18360  const unsigned j_shd_bnd =
18361  this->shared_boundaries_ids(my_rank, jproc, bb);
18362  // Is the node part of this boundary?
18363  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
18364  {
18365 // DEBP("Sending to");
18366 // DEBP(iproc);
18367 // DEBP("Pair of procs where other shared");
18368 // DEBP(my_rank);
18369 // DEBP(jproc);
18370 // DEBP(i_bnd);
18371  node_on_shared_boundary_with_other_processors = true;
18372  // Increase the counter for the number of shared boundaries
18373  // with other processors the node is on
18374  nshared_boundaries_with_other_processors_have_node++;
18375  } // if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt)
18376 
18377  } // for (bb<n_jshd_bnd)
18378 
18379  } // if (jproc != iproc)
18380 
18381  } // for (jproc < nproc)
18382 
18383  // If the node is on a shared boundary with another processor
18384  // (my_rank, jproc), then send the flag and look for the info.
18385  if (node_on_shared_boundary_with_other_processors)
18386  {
18387  Flat_packed_unsigneds.push_back(4);
18388 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18389  Flat_packed_unsigneds_string.push_back("Node is on shared boundary no related with the received processor: 4");
18390 #endif
18391 
18392  // The number of packages of information that will be sent to the
18393  // "iproc" processor. This helps to know how many packages of data
18394  // read from the received processor
18395  Flat_packed_unsigneds.push_back(nshared_boundaries_with_other_processors_have_node);
18396 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18397  std::stringstream junk;
18398  junk << "Number of other shared boundaries that the node is on: "
18399  << nshared_boundaries_with_other_processors_have_node;
18400  Flat_packed_unsigneds_string.push_back(junk.str());
18401 #endif
18402 
18403  // Counter to ensure that the correct number of data has been sent
18404  unsigned counter_shd_bnd_with_other_procs_have_node = 0;
18405  // Loop over the shared boundaries with other processors and get:
18406  // 1) The processors defining the shared boundary
18407  // 2) The shared boundary id
18408  // 3) The index of the node on the shared boundary
18409  Vector<unsigned> other_processor_1;
18410  Vector<unsigned> other_processor_2;
18411  Vector<unsigned> shd_bnd_ids;
18412  Vector<unsigned> indexes;
18413  // Loop over the processors again
18414  for (unsigned jproc = 0; jproc < nproc; jproc++)
18415  {
18416  // Do not search with the iproc processor, that was done before
18417  // above
18418  if (jproc != iproc)
18419  {
18420  // Get the number of shared boundaries with the jproc
18421  // processor
18422  const unsigned n_jshd_bnd =
18423  this->nshared_boundaries(my_rank, jproc);
18424  for (unsigned bb = 0; bb < n_jshd_bnd; bb++)
18425  {
18426  // Get the boundary id
18427  const unsigned j_shd_bnd =
18428  this->shared_boundaries_ids(my_rank, jproc, bb);
18429  // Is the node part of this boundary?
18430  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
18431  {
18432  // Include the first processor
18433  other_processor_1.push_back(my_rank);
18434  // Include the second processor
18435  other_processor_2.push_back(jproc);
18436  // Include the shared boundary id
18437  shd_bnd_ids.push_back(j_shd_bnd);
18438  // Increase the counter for found shared boundaries with
18439  // other processors
18440  counter_shd_bnd_with_other_procs_have_node++;
18441  }
18442 
18443  } // for (bb < nshared_bnd)
18444 
18445  } // if (jproc != iproc)
18446 
18447  } // for (jproc < nproc)
18448 
18449  // Get the indexes of the node on all the shared boundaries where
18450  // it was found
18451  const unsigned n_other_processors = other_processor_1.size();
18452  // Loop over the processors where the node was found
18453  for (unsigned i = 0; i < n_other_processors; i++)
18454  {
18455  // Get the shared boundary id
18456  unsigned shd_bnd_id = shd_bnd_ids[i];
18457  // Get the number of nodes on that shared boundary
18458  const unsigned n_nodes_on_shd_bnd =
18459  nsorted_shared_boundary_node(shd_bnd_id);
18460 
18461 #ifdef PARANOID
18462  bool found_index_node_on_shared_boundary = false;
18463 #endif
18464  for (unsigned i = 0; i < n_nodes_on_shd_bnd; i++)
18465  {
18466  // Get the i-th shared boundary node
18467  Node* shared_node_pt =
18468  sorted_shared_boundary_node_pt(shd_bnd_id, i);
18469  // Is the same node?
18470  if (shared_node_pt == nod_pt)
18471  {
18472 // DEBP(i_node);
18473 // DEBP(nod_pt->x(0));
18474 // DEBP(nod_pt->x(1));
18475  // Include the index of the node
18476  indexes.push_back(i);
18477 #ifdef PARANOID
18478  // Mark as found the node
18479  found_index_node_on_shared_boundary = true;
18480 #endif
18481  break;
18482  } // if (shared_node_pt == nod_pt)
18483 
18484  } // for (i < n_nodes_on_shd_bnd)
18485 
18486 #ifdef PARANOID
18487  if (!found_index_node_on_shared_boundary)
18488  {
18489  std::ostringstream error_message;
18490  error_message
18491  <<"The index of the node on boundary ("
18492  <<shd_bnd_id<<"), shared by other processors\nwas not found.\n"
18493  <<"The node coordinates are ("<<nod_pt->x(0)<<","
18494  <<nod_pt->x(1)<<").\n";
18495  throw OomphLibError(
18496  error_message.str(),
18497  "RefineableTriangleMesh::get_required_nodal_information_helper()",
18498  OOMPH_EXCEPTION_LOCATION);
18499  }
18500 #endif
18501  } // for (i < n_other_processors)
18502 
18503  // Now send the info. but first check that the number of found
18504  // nodes be the same that the previously found shared boundaries
18505  // with the node
18506 #ifdef PARANOID
18507  if (counter_shd_bnd_with_other_procs_have_node !=
18508  nshared_boundaries_with_other_processors_have_node)
18509  {
18510  std::ostringstream error_message;
18511  error_message
18512  <<"The number of shared boundaries where the node is on "
18513  <<"is different:\n"
18514  << "nshared_boundaries_with_other_processors_have_node: ("
18515  << nshared_boundaries_with_other_processors_have_node
18516  << ")\n"
18517  << "counter_shd_bnd_with_other_procs_have_node: ("
18518  << counter_shd_bnd_with_other_procs_have_node
18519  << ")\n";
18520  throw OomphLibError(
18521  error_message.str(),
18522  "RefineableTriangleMesh::get_required_nodal_information_helper()",
18523  OOMPH_EXCEPTION_LOCATION);
18524  } // if (counter_shd_bnd_with_other_procs_have_node !=
18525  // nshared_boundaries_with_other_processors_have_node)
18526 #endif
18527 
18528  // Loop over the info. to send it
18529  for (unsigned i = 0; i < n_other_processors; i++)
18530  {
18531  Flat_packed_unsigneds.push_back(other_processor_1[i]);
18532 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18533  std::stringstream junk1;
18534  junk1 << "Processor where the other shared boundary "
18535  << "has the node: " << other_processor_1[i];
18536  Flat_packed_unsigneds_string.push_back(junk1.str());
18537 #endif
18538 
18539  Flat_packed_unsigneds.push_back(other_processor_2[i]);
18540 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18541  std::stringstream junk2;
18542  junk2 << "Processor where the other shared boundary "
18543  << "has the node: " << other_processor_2[i];
18544  Flat_packed_unsigneds_string.push_back(junk2.str());
18545 #endif
18546 
18547  Flat_packed_unsigneds.push_back(shd_bnd_ids[i]);
18548 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18549  std::stringstream junk3;
18550  junk3 << "Other shared boundary id where the node is on"
18551  << boundaries[i];
18552  Flat_packed_unsigneds_string.push_back(junk3.str());
18553 #endif
18554 
18555  Flat_packed_unsigneds.push_back(indexes[i]);
18556 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18557  std::stringstream junk4;
18558  junk4 << "Node index on other shared boundary "
18559  <<boundaries[i] << " is "
18560  << indexes[i];
18561  Flat_packed_unsigneds_string.push_back(junk4.str());
18562 #endif
18563 
18564  } // for (i < n_other_processors)
18565 
18566  } // if (node_on_shared_boundary_with_other_processors)
18567  else
18568  {
18569  Flat_packed_unsigneds.push_back(0);
18570 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18571  Flat_packed_unsigneds_string.push_back("Node is on any shared boundary with other processors");
18572 #endif
18573  } // else if (node_on_shared_boundary_with_other_processors)
18574 
18575  // Now check if it is required to send the info. of the node. If the
18576  // node is not on a shared boundary with the iproc processor then we
18577  // need to send the info.
18578 
18579  if (!node_on_shared_boundary)
18580  {
18581  // Send all the info. to create it
18582 
18583  // Is the Node algebraic? If so, send its ref values and
18584  // an indication of its geometric objects if they are stored
18585  // in the algebraic mesh
18586  AlgebraicNode* alg_nod_pt=dynamic_cast<AlgebraicNode*>(nod_pt);
18587  if (alg_nod_pt!=0)
18588  {
18589  // The external mesh should be algebraic
18590  AlgebraicMesh* alg_mesh_pt=dynamic_cast<AlgebraicMesh*>(this);
18591 
18592  // Get default node update function ID
18593  unsigned update_id=alg_nod_pt->node_update_fct_id();
18594  Flat_packed_unsigneds.push_back(update_id);
18595 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18596  Flat_packed_unsigneds_string.push_back("Alg Node update id");
18597 #endif
18598 
18599  // Get reference values at default...
18600  unsigned n_ref_val=alg_nod_pt->nref_value();
18601  Flat_packed_unsigneds.push_back(n_ref_val);
18602 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18603  Flat_packed_unsigneds_string.push_back("Alg Node n ref values");
18604 #endif
18605  for (unsigned i_ref_val=0;i_ref_val<n_ref_val;i_ref_val++)
18606  {
18607  Flat_packed_doubles.push_back(alg_nod_pt->ref_value(i_ref_val));
18608  }
18609 
18610  // Access geometric objects at default...
18611  unsigned n_geom_obj=alg_nod_pt->ngeom_object();
18612  Flat_packed_unsigneds.push_back(n_geom_obj);
18613 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18614  Flat_packed_unsigneds_string.push_back("Alg Node n geom objects");
18615 #endif
18616  for (unsigned i_geom=0;i_geom<n_geom_obj;i_geom++)
18617  {
18618  GeomObject* geom_obj_pt=alg_nod_pt->geom_object_pt(i_geom);
18619 
18620  // Check this against the stored geometric objects in mesh
18621  unsigned n_geom_list=alg_mesh_pt->ngeom_object_list_pt();
18622 
18623  // Default found index to zero
18624  unsigned found_geom_object=0;
18625  for (unsigned i_list=0;i_list<n_geom_list;i_list++)
18626  {
18627  if (geom_obj_pt==alg_mesh_pt->geom_object_list_pt(i_list))
18628  {
18629  found_geom_object=i_list;
18630  }
18631  }
18632  Flat_packed_unsigneds.push_back(found_geom_object);
18633 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18634  Flat_packed_unsigneds_string.push_back("Found geom object");
18635 #endif
18636  }
18637  } // (if alg_nod_pt!=0)
18638 
18639  // Is it a SolidNode?
18640  SolidNode* solid_nod_pt=dynamic_cast<SolidNode*>(nod_pt);
18641  if (solid_nod_pt!=0)
18642  {
18643  unsigned n_solid_val=solid_nod_pt->variable_position_pt()->nvalue();
18644  for (unsigned i_val=0;i_val<n_solid_val;i_val++)
18645  {
18646  for (unsigned t=0;t<n_prev;t++)
18647  {
18648  Flat_packed_doubles.push_back(solid_nod_pt->variable_position_pt()->
18649  value(t,i_val));
18650  }
18651  }
18652 
18653  Vector<double> values_solid_node;
18654  solid_nod_pt->add_values_to_vector(values_solid_node);
18655  const unsigned nvalues_solid_node = values_solid_node.size();
18656  Flat_packed_unsigneds.push_back(nvalues_solid_node);
18657 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18658  std::stringstream junk;
18659  junk << "Number of values solid node: "
18660  << nvalues_solid_node;
18661  Flat_packed_unsigneds_string.push_back(junk.str());
18662 #endif
18663  for (unsigned i = 0; i < nvalues_solid_node; i++)
18664  {
18665  Flat_packed_doubles.push_back(values_solid_node[i]);
18666  }
18667  }
18668 
18669  // Finally copy info required for all node types
18670  for (unsigned i_val=0;i_val<n_val;i_val++)
18671  {
18672  for (unsigned t=0;t<n_prev;t++)
18673  {
18674  Flat_packed_doubles.push_back(nod_pt->value(t,i_val));
18675  }
18676  }
18677 
18678  // Now do positions
18679  for (unsigned idim=0;idim<n_dim;idim++)
18680  {
18681  for (unsigned t=0;t<n_prev;t++)
18682  {
18683  Flat_packed_doubles.push_back(nod_pt->x(t,idim));
18684  }
18685  }
18686 
18687  } // if (!node_on_shared_boundary)
18688 
18689  }
18690 
18691  //==========start of add_haloed_node_helper===============================
18692  /// Helper to add external haloed node that is not a master
18693  //========================================================================
18694  template<class ELEMENT>
18696  add_haloed_node_helper(unsigned& iproc, Node* nod_pt)
18697  {
18698  // Attempt to add this node as a haloed node
18699  const unsigned n_haloed_nod = this->nhaloed_node(iproc);
18700  const unsigned haloed_node_index =
18701  this->try_to_add_haloed_node_pt(iproc,nod_pt);
18702 
18703  // If it was added then the new index should match the size of the storage
18704  if (haloed_node_index==n_haloed_nod)
18705  {
18706  Flat_packed_unsigneds.push_back(1);
18707 
18708 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18709  std::stringstream junk;
18710  junk << "Node needs to be constructed [size="
18711  << Flat_packed_unsigneds.size() << "]; last entry: "
18712  << Flat_packed_unsigneds[Flat_packed_unsigneds.size()-1];
18713  Flat_packed_unsigneds_string.push_back(junk.str());
18714 #endif
18715 
18716  // This helper function gets all the required information for the
18717  // specified node and stores it into MPI-sendable information
18718  // so that a halo copy can be made on the receiving process
18719  get_required_nodal_information_helper(iproc, nod_pt);
18720  }
18721  else // It was already added
18722  {
18723  Flat_packed_unsigneds.push_back(0);
18724 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18725  std::stringstream junk;
18726  junk << "Node was already added [size="
18727  << Flat_packed_unsigneds.size() << "]; last entry: "
18728  << Flat_packed_unsigneds[Flat_packed_unsigneds.size()-1];
18729 
18730  Flat_packed_unsigneds_string.push_back(junk.str());
18731 #endif
18732 
18733  // This node is already a haloed node, so tell
18734  // the other process its index in the equivalent halo storage
18735  Flat_packed_unsigneds.push_back(haloed_node_index);
18736 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18737  Flat_packed_unsigneds_string.push_back("haloed node index");
18738 #endif
18739  }
18740 
18741  }
18742 
18743  //================= send_and_receive_haloed_info =======================
18744  /// Send the information of the elements that will be created on the other
18745  /// processor
18746  //======================================================================
18747  template<class ELEMENT>
18749  send_and_receive_elements_nodes_info(int &send_proc, int &recv_proc)
18750  {
18751  // Get the communicator of the mesh
18752  OomphCommunicator* comm_pt = this->communicator_pt();
18753 
18754  // Set MPI info
18755  MPI_Status status;
18756  MPI_Request request;
18757 
18758  // Prepare vectors to receive information
18759  Vector<double> received_double_values;
18760  Vector<unsigned> received_unsigned_values;
18761 
18762  // Send the double values associated with halo(ed) elements and nodes
18763  //-------------------------------------------------------------------
18764  unsigned send_count_double_values=Flat_packed_doubles.size();
18765  MPI_Isend(&send_count_double_values,1,MPI_UNSIGNED,
18766  send_proc,1,comm_pt->mpi_comm(),&request);
18767 
18768  int receive_count_double_values=0;
18769  MPI_Recv(&receive_count_double_values,1,MPI_INT,
18770  recv_proc,1,comm_pt->mpi_comm(),&status);
18771  MPI_Wait(&request,MPI_STATUS_IGNORE);
18772 
18773  if (send_count_double_values!=0)
18774  {
18775  MPI_Isend(&Flat_packed_doubles[0],send_count_double_values,MPI_DOUBLE,
18776  send_proc,2,comm_pt->mpi_comm(),&request);
18777  }
18778  if (receive_count_double_values!=0)
18779  {
18780  received_double_values.resize(receive_count_double_values);
18781  MPI_Recv(&received_double_values[0],receive_count_double_values,
18782  MPI_DOUBLE,recv_proc,2,comm_pt->mpi_comm(),&status);
18783  }
18784  if (send_count_double_values!=0)
18785  {
18786  MPI_Wait(&request,MPI_STATUS_IGNORE);
18787  }
18788 
18789  // Now send unsigned values associated with halo(ed) elements and nodes
18790  //---------------------------------------------------------------------
18791  unsigned send_count_unsigned_values=Flat_packed_unsigneds.size();
18792 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18793  unsigned send_count_unsigned_string=Flat_packed_unsigneds_string.size();
18794 #ifdef PARANOID
18795  if (send_count_unsigned_string != send_count_unsigned_values)
18796  {
18797  std::ostringstream error_message;
18798  error_message
18799  << "The number of unsigned values to send to processor ("
18800  << send_proc << ") is different from the\nnumber of annotated strings "
18801  << "for the communication\n\n";
18802  throw OomphLibError(error_message.str(),
18803  OOMPH_CURRENT_FUNCTION,
18804  OOMPH_EXCEPTION_LOCATION);
18805  }
18806 #endif // #ifdef PARANOID
18807 #endif
18808  MPI_Isend(&send_count_unsigned_values,1,MPI_UNSIGNED,
18809  send_proc,14,comm_pt->mpi_comm(),&request);
18810 
18811  int receive_count_unsigned_values=0;
18812  MPI_Recv(&receive_count_unsigned_values,1,MPI_INT,recv_proc,14,
18813  comm_pt->mpi_comm(),&status);
18814 
18815  MPI_Wait(&request,MPI_STATUS_IGNORE);
18816 
18817  if (send_count_unsigned_values!=0)
18818  {
18819  MPI_Isend(&Flat_packed_unsigneds[0],send_count_unsigned_values,
18820  MPI_UNSIGNED,send_proc,15,comm_pt->mpi_comm(),&request);
18821 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18822  for (unsigned i=0;i<send_count_unsigned_values;i++)
18823  {
18824  oomph_info << "Sent:" << i << " to orig_proc:" << send_proc
18825  << " " << Flat_packed_unsigneds_string[i]
18826  << ": " << Flat_packed_unsigneds[i] << std::endl;
18827  }
18828 #endif
18829  }
18830  if (receive_count_unsigned_values!=0)
18831  {
18832  received_unsigned_values.resize(receive_count_unsigned_values);
18833  MPI_Recv(&received_unsigned_values[0],receive_count_unsigned_values,
18834  MPI_UNSIGNED,recv_proc,15,comm_pt->mpi_comm(),&status);
18835  }
18836 
18837  if (send_count_unsigned_values!=0)
18838  {
18839  MPI_Wait(&request,MPI_STATUS_IGNORE);
18840  }
18841 
18842  // Copy across into original containers -- these can now
18843  //------------------------------------------------------
18844  // be processed by create_external_halo_elements() to generate
18845  //------------------------------------------------------------
18846  // external halo elements
18847  //------------------------
18848  Flat_packed_doubles.resize(receive_count_double_values);
18849  for (int ii=0;ii<receive_count_double_values;ii++)
18850  {
18851  Flat_packed_doubles[ii]=received_double_values[ii];
18852  }
18853  Flat_packed_unsigneds.resize(receive_count_unsigned_values);
18854  for (int ii=0;ii<receive_count_unsigned_values;ii++)
18855  {
18856  Flat_packed_unsigneds[ii]=received_unsigned_values[ii];
18857  }
18858 
18859  }
18860 
18861  //=====================================================================
18862  /// Creates (halo) element on the loop process based on the
18863  /// information received from each processor
18864  //=====================================================================
18865  template<class ELEMENT>
18867  create_halo_element(unsigned& iproc,
18868  Vector<Node*> &new_nodes_on_domain,
18869  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
18870  &other_proc_shd_bnd_node_pt,
18871  Vector<Vector<Vector<unsigned> > >
18872  &global_node_names,
18873  std::map<Vector<unsigned>, unsigned>
18874  &node_name_to_global_index,
18875  Vector<Node*> &global_shared_node_pt)
18876  {
18877 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18878  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
18879  << " Bool: New element needs to be constructed "
18880  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
18881  << std::endl;
18882 #endif
18883 
18884  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]==1)
18885  {
18886  // Create a new element from the communicated values
18887  // and coords from the process that located zeta
18888  GeneralisedElement *new_el_pt= new ELEMENT;
18889 
18890  // Add the element, it is a new element in the mesh
18891  this->add_element_pt(new_el_pt);
18892 
18893  // Add halo element to this mesh
18894  this->add_root_halo_element_pt(iproc, new_el_pt);
18895 
18896  // Cast to the FE pointer
18897  FiniteElement* f_el_pt=dynamic_cast<FiniteElement*>(new_el_pt);
18898 
18899  // Check if new element is associated to any boundary
18900  this->add_halo_element_helper(iproc,f_el_pt);
18901 
18902  // Now we add nodes to the new element
18903  unsigned n_node=f_el_pt->nnode();
18904 
18905  for (unsigned j=0;j<n_node;j++)
18906  {
18907  Node* new_nod_pt=0;
18908 
18909  // Call the add halo node helper function
18910  add_halo_node_helper(new_nod_pt,
18911  new_nodes_on_domain,
18912  other_proc_shd_bnd_node_pt,
18913  iproc, j, f_el_pt,
18914  global_node_names,
18915  node_name_to_global_index,
18916  global_shared_node_pt);
18917 
18918  } // for (j<n_nod)
18919 
18920  }
18921  else // the element already exists as halo
18922  {
18923 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18924  oomph_info
18925  << "Rec:" << Counter_for_flat_packed_unsigneds
18926  << " Index of existing halo element "
18927  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
18928  << std::endl;
18929 #endif
18930  // The index itself is in Flat_packed_unsigneds[...]
18931  unsigned halo_ele_index=
18932  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
18933 
18934  // Use this index to get the element
18935  FiniteElement* f_el_pt=
18936  dynamic_cast<FiniteElement*>(this->root_halo_element_pt(iproc,
18937  halo_ele_index));
18938 
18939  //If it's not a finite element die
18940  if(f_el_pt==0)
18941  {
18942  throw OomphLibError("Halo element is not a FiniteElement\n",
18943  OOMPH_CURRENT_FUNCTION,
18944  OOMPH_EXCEPTION_LOCATION);
18945  }
18946 
18947  } // else the element already exists as halo
18948 
18949  }
18950 
18951  //========start of add_halo_element_helper==============================
18952  /// \short Helper function to create (halo) elements on the loop
18953  /// process based on the info received in send_and_received_located_info
18954  /// This function is in charge of verify if the element is associated to
18955  /// a boundary
18956  //======================================================================
18957  template<class ELEMENT>
18959  add_halo_element_helper(unsigned& iproc, FiniteElement* ele_pt)
18960  {
18961 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18962  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
18963  << " Bool: Element is associated to an original boundary "
18964  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
18965  << std::endl;
18966 #endif
18967 
18968  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]==1)
18969  {
18970 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18971  oomph_info
18972  << "Rec:" << Counter_for_flat_packed_unsigneds
18973  << " How many boundaries are associated with the element "
18974  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
18975  << std::endl;
18976 #endif
18977  const unsigned nassociated_boundaries =
18978  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
18979 
18980  for (unsigned b = 0; b < nassociated_boundaries; b++)
18981  {
18982 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18983  oomph_info
18984  << "Rec:" << Counter_for_flat_packed_unsigneds
18985  << " Boundary associated to the element "
18986  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
18987  << std::endl;
18988 #endif
18989  const unsigned bnd =
18990  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
18991 
18992 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
18993  oomph_info
18994  << "Rec:" << Counter_for_flat_packed_unsigneds
18995  << " Face index of the element "
18996  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
18997  << std::endl;
18998 #endif
18999  const unsigned face_index =
19000  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19001 
19002  // Associate the element with the boundary and establish as many
19003  // face indexes it has
19004  this->Boundary_element_pt[bnd].push_back(ele_pt);
19005  this->Face_index_at_boundary[bnd].push_back(face_index);
19006 
19007  } // (b < nassociated_boundaries)
19008 
19009  // Here read the info. regarding the boundary-region of the element
19010 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19011  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19012  << " Bool: Element is associated to a boundary-region "
19013  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19014  << std::endl;
19015 #endif
19016 
19017  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]==1)
19018  {
19019 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19020  oomph_info
19021  << "Rec:" << Counter_for_flat_packed_unsigneds
19022  << " How many boundaries-regions are associated with the element "
19023  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19024  << std::endl;
19025 #endif
19026  const unsigned nassociated_boundaries_and_regions =
19027  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19028 
19029  for (unsigned br = 0; br < nassociated_boundaries_and_regions; br++)
19030  {
19031 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19032  oomph_info
19033  << "Rec:" << Counter_for_flat_packed_unsigneds
19034  << " Boundary associated to the element "
19035  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19036  << std::endl;
19037 #endif
19038  const unsigned bnd =
19039  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19040 
19041 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19042  oomph_info
19043  << "Rec:" << Counter_for_flat_packed_unsigneds
19044  << " Region associated to the element "
19045  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19046  << std::endl;
19047 #endif
19048  const unsigned region =
19049  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19050 
19051 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19052  oomph_info
19053  << "Rec:" << Counter_for_flat_packed_unsigneds
19054  << " Face index of the element in boundary-region "
19055  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19056  << std::endl;
19057 #endif
19058  const unsigned face_index =
19059  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19060 
19061  // Associate the element with the boundary-regions and establish
19062  // as many face indexes it has
19063  this->Boundary_region_element_pt[bnd][region].push_back(ele_pt);
19064  this->Face_index_region_at_boundary[bnd][region].push_back(face_index);
19065 
19066  } // for (br < nassociated_boundaries_and_regions)
19067 
19068  } // Is the element associated with a boundary-region?
19069 
19070  }
19071 
19072  // Now check if the element is associated to a shared boundary
19073 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19074  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19075  << " Bool: Element is associated to a shared boundary "
19076  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19077  << std::endl;
19078 #endif
19079  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]==3)
19080  {
19081 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19082  oomph_info
19083  << "Rec:" << Counter_for_flat_packed_unsigneds
19084  << " How many shared boundaries are associated with the element "
19085  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19086  << std::endl;
19087 #endif
19088  const unsigned nassociated_shared_boundaries =
19089  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19090 
19091  for (unsigned b = 0; b < nassociated_shared_boundaries; b++)
19092  {
19093 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19094  oomph_info
19095  << "Rec:" << Counter_for_flat_packed_unsigneds
19096  << " Shared boundary associated to the element "
19097  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19098  << std::endl;
19099 #endif
19100  const unsigned bnd =
19101  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19102 
19103 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19104  oomph_info
19105  << "Rec:" << Counter_for_flat_packed_unsigneds
19106  << " Face index of the element associated to the shared boundary "
19107  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19108  << std::endl;
19109 #endif
19110 
19111  const unsigned face_index =
19112  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19113 
19114  this->add_shared_boundary_element(bnd, ele_pt);
19115  this->add_face_index_at_shared_boundary(bnd, face_index);
19116 
19117  } // (b < nassociated_shared_boundaries)
19118 
19119  } // The element is associted with a shared boundary
19120 
19121  }
19122 
19123  //========start of add_halo_node_helper==========================
19124  /// Helper function to add halo node
19125  //===============================================================
19126  template<class ELEMENT>
19128  (Node* &new_nod_pt,
19129  Vector<Node*> &new_nodes_on_domain,
19130  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
19131  &other_proc_shd_bnd_node_pt,
19132  unsigned& iproc,
19133  unsigned& node_index,
19134  FiniteElement* const &new_el_pt,
19135  Vector<Vector<Vector<unsigned> > > &global_node_names,
19136  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
19137  Vector<Node*> &global_shared_node_pt)
19138  {
19139  // Given the node, received information about them from process
19140  // iproc, construct them on the current process
19141 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19142  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19143  << " Bool: New node needs to be constructed "
19144  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19145  << std::endl;
19146 #endif
19147  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]==1)
19148  {
19149  // Construct a new node based upon sent information, or copy a node
19150  // from one of the shared boundaries
19151  construct_new_halo_node_helper(new_nod_pt, new_nodes_on_domain,
19152  other_proc_shd_bnd_node_pt,
19153  iproc, node_index, new_el_pt,
19154  global_node_names,
19155  node_name_to_global_index,
19156  global_shared_node_pt);
19157  }
19158  else
19159  {
19160 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19161  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19162  << " Index of existing halo node "
19163  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19164  << std::endl;
19165 #endif
19166 
19167  // Copy node from received location
19168  new_nod_pt = new_nodes_on_domain[
19169  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]];
19170 
19171  new_el_pt->node_pt(node_index)=new_nod_pt;
19172 
19173  }
19174 
19175  }
19176 
19177  //========start of construct_new_halo_node_helper=================
19178  //Helper function which constructs a new external halo node (on new element)
19179  //with the required information sent from the haloed process
19180  //========================================================================
19181  template<class ELEMENT>
19183  (Node* &new_nod_pt,
19184  Vector<Node*> &new_nodes_on_domain,
19185  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
19186  &other_proc_shd_bnd_node_pt,
19187  unsigned& iproc, unsigned& node_index,
19188  FiniteElement* const &new_el_pt,
19189  Vector<Vector<Vector<unsigned> > > &global_node_names,
19190  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
19191  Vector<Node*> &global_shared_node_pt)
19192  {
19193  //The first entry indicates the number of values at this new Node
19194  //(which may be different across the same element e.g. Lagrange multipliers)
19195 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19196  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19197  << " Number of values of external halo node "
19198  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19199  << std::endl;
19200 #endif
19201  unsigned n_val=Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19202 
19203  // Null TimeStepper for now
19204  TimeStepper* time_stepper_pt=this->Time_stepper_pt;
19205  // Default number of previous values to 1
19206  unsigned n_prev=time_stepper_pt->ntstorage();
19207 
19208  // ------------------------------------------------------
19209  // Check if the node is on an original boundary
19210 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19211  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19212  << " Is the node on an original boundary "
19213  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19214  << std::endl;
19215 #endif
19216 
19217  // Flag to indicate if the node is on original boundaries
19218  const unsigned node_on_original_boundaries =
19219  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19220 
19221  // Store the original boundaries where the node is on
19222  Vector<unsigned> original_boundaries_node_is_on;
19223  // Store the zeta coordinates of the node on the original boundaries
19224  Vector<double> zeta_coordinates;
19225  // Store the number of original boundaries the node is on
19226  unsigned n_original_boundaries_node_is_on = 0;
19227 
19228  if (node_on_original_boundaries==2)
19229  {
19230  // How many original boundaries does the node live on?
19231 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19232  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19233  << " Number of boundaries the node is on: "
19234  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19235  << std::endl;
19236 #endif
19237  n_original_boundaries_node_is_on =
19238  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19239 
19240  // Resize the containers
19241  original_boundaries_node_is_on.resize(n_original_boundaries_node_is_on);
19242  zeta_coordinates.resize(n_original_boundaries_node_is_on);
19243 
19244  for (unsigned i=0;i<n_original_boundaries_node_is_on;i++)
19245  {
19246  // Boundary number
19247 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19248  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19249  << " Node is on boundary "
19250  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19251  << std::endl;
19252 #endif
19253  original_boundaries_node_is_on[i] =
19254  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19255  zeta_coordinates[i] =
19256  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
19257  }
19258 
19259  } // if (node_on_original_boundaries==2)
19260 #ifdef PARANOID
19261  else
19262  {
19263  if (node_on_original_boundaries != 0)
19264  {
19265  std::ostringstream error_message;
19266  error_message
19267  <<"The current node is not on an original boundary, this should\n"
19268  <<"be indicated by a zero flag. However, the read value for\n"
19269  <<"that flag is ("<<node_on_original_boundaries<<").\n\n";
19270  throw OomphLibError(
19271  error_message.str(),
19272  "RefineableTriangleMesh::construct_new_halo_node_helper()",
19273  OOMPH_EXCEPTION_LOCATION);
19274  } // if (node_on_original_boundaries != 0)
19275  }
19276 #endif
19277 
19278  // --------------------------------------------------------------
19279  // Check if the node was on a shared boundary with the iproc
19280  // processor
19281 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19282  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19283  << " Is node on shared boundary? "
19284  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19285  << std::endl;
19286 #endif
19287  const unsigned is_node_on_shared_boundary =
19288  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19289  if (is_node_on_shared_boundary == 1)
19290  {
19291  // How many shared boundaries does the node live on?
19292 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19293  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19294  << " Number of boundaries the node is on: "
19295  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19296  << std::endl;
19297 #endif
19298  const unsigned n_shd_bnd_node_is_on =
19299  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19300  Vector<unsigned> shd_bnds_node_is_on(n_shd_bnd_node_is_on);
19301  for (unsigned i=0;i<n_shd_bnd_node_is_on;i++)
19302  {
19303  // Shared boundary number
19304 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19305  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19306  << " Node is on boundary "
19307  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19308  << std::endl;
19309 #endif
19310  shd_bnds_node_is_on[i] =
19311  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19312  }
19313 
19314  // Get the index of the node on the shared boundary
19315 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19316  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19317  << " Index of node on boundary "
19318  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19319  << std::endl;
19320 #endif
19321  // Get the node index of the node on the shared boundary
19322  unsigned node_index_on_shared_boundary =
19323  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19324 
19325  // Get the pointer to the node with the received info.
19326  new_nod_pt =
19327  this->sorted_shared_boundary_node_pt(shd_bnds_node_is_on[0],
19328  node_index_on_shared_boundary);
19329 
19330  } // if (is_node_on_shared_boundary == 1)
19331 #ifdef PARANOID
19332  else
19333  {
19334  if (is_node_on_shared_boundary != 0)
19335  {
19336  std::ostringstream error_message;
19337  error_message
19338  <<"The current node is not on a shared boundary, this should\n"
19339  <<"be indicated by a zero flag. However, the read value for\n"
19340  <<"that flag is ("<<is_node_on_shared_boundary<<").\n\n";
19341  throw OomphLibError(
19342  error_message.str(),
19343  "RefineableTriangleMesh::construct_new_halo_node_helper()",
19344  OOMPH_EXCEPTION_LOCATION);
19345  } // if (node_on_shared_boundary != 0)
19346  }
19347 #endif
19348 
19349  // ------------------------------------------------------------
19350  // Is the node on a shared boundary with other processor?
19351 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19352  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19353  << " Is the node on shared boundaries with other processors "
19354  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19355  << std::endl;
19356 #endif
19357 
19358  // Is the node in shared boundaries no associated with the
19359  // receiver processor
19360  const unsigned is_the_node_in_shared_boundaries_with_other_processors =
19361  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19362 
19363  // The containers where to store the info.
19364  Vector<unsigned> other_processor_1;
19365  Vector<unsigned> other_processor_2;
19366  Vector<unsigned> other_shared_boundaries;
19367  Vector<unsigned> other_indexes;
19368 
19369  // How many shared bounaries with other processors the node lives on
19370  unsigned n_shd_bnd_with_other_procs_have_node = 0;
19371 
19372  // Is the node on shared boundaries with other processors
19373  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19374  {
19375 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19376  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19377  << " In how many shared boundaries with other "
19378  << "processors is the node "
19379  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19380  << std::endl;
19381 #endif
19382 
19383  // How many nodes on other shared boundaries were found
19384  n_shd_bnd_with_other_procs_have_node =
19385  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19386 
19387  // Resize the containers
19388  other_processor_1.resize(n_shd_bnd_with_other_procs_have_node);
19389  other_processor_2.resize(n_shd_bnd_with_other_procs_have_node);
19390  other_shared_boundaries.resize(n_shd_bnd_with_other_procs_have_node);
19391  other_indexes.resize(n_shd_bnd_with_other_procs_have_node);
19392 
19393  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
19394  {
19395 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19396  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19397  << " Processor where the other shared boundary"
19398  << "has the node"
19399  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19400  << std::endl;
19401 #endif
19402  // Read the other processor 1
19403  other_processor_1[i] =
19404  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19405 
19406 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19407  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19408  << " Processor where the other shared boundary"
19409  << "has the node"
19410  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19411  << std::endl;
19412 #endif
19413  // Read the other processor 2
19414  other_processor_2[i] =
19415  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19416 
19417 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19418  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19419  << " Other shared boundary id where the node is on: "
19420  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19421  << std::endl;
19422 #endif
19423 
19424  // Read the other shared boundary id
19425  other_shared_boundaries[i] =
19426  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19427 
19428 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19429  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19430  << " Node index on the other shared boundary "
19431  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19432  << std::endl;
19433 #endif
19434 
19435  // Read the node index on the other shared boundary
19436  other_indexes[i] =
19437  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19438 
19439  } // for (i < n_shd_bnd_with_other_procs_have_node)
19440 
19441  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19442 #ifdef PARANOID
19443  else
19444  {
19445  if (is_the_node_in_shared_boundaries_with_other_processors != 0)
19446  {
19447  std::ostringstream error_message;
19448  error_message
19449  <<"The current node is not on a shared boundary with\n"
19450  <<"other processors, this should be indicated by a zero flag.\n"
19451  <<"However, the read value for that flag is ("
19452  <<is_the_node_in_shared_boundaries_with_other_processors<<").\n\n";
19453  throw OomphLibError(
19454  error_message.str(),
19455  "RefineableTriangleMesh::construct_new_halo_node_helper()",
19456  OOMPH_EXCEPTION_LOCATION);
19457  }
19458  }
19459 #endif
19460 
19461  // Now we have all the info. to decide whether the node should be
19462  // created or not
19463 
19464  // First check if the node is a shared boundary node
19465  if (is_node_on_shared_boundary == 1)
19466  {
19467  // We already have the node, we do not need to create it
19468 
19469  // Only check if we need to add boundary info. to the node
19470  if (node_on_original_boundaries==2)
19471  {
19472  // The node is a boundary node, add the boundary info. before
19473  // adding it to the domain
19474 
19475  // Associate the node to the given boundaries
19476  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
19477  {
19478  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
19479  // Establish the boundary coordinates for the node
19480  Vector<double> zeta(1);
19481  zeta[0] = zeta_coordinates[i];
19482  new_nod_pt->set_coordinates_on_boundary(
19483  original_boundaries_node_is_on[i],zeta);
19484  }
19485 
19486  } // if (node_on_original_boundaries==2)
19487 
19488  // Add the node to the domain
19489  new_nodes_on_domain.push_back(new_nod_pt);
19490 
19491  // Add the node to the element
19492  new_el_pt->node_pt(node_index) = new_nod_pt;
19493 
19494  } // if (is_node_on_shared_boundary == 1)
19495 
19496  // Now check if the node is on a shared boundary with another
19497  // processor, if that is the case try to find the node that may have
19498  // been already sent by the other processors
19499 
19500  // This flags indicates if the node was found, and then decide if it
19501  // is required to create the node
19502  bool found_node_in_other_shared_boundaries = false;
19503  // Flag to indicate whether the node should be created as a boundary
19504  // node or not. If the node lies on a shared boundary with other
19505  // processor the we create it as a boundary node. The processor from
19506  // which we are receiving info. (iproc) may not know that the node
19507  // lies on an original boundary. If the node lies on an original
19508  // boundary then its info. will be sent by another processor, then
19509  // we can set its boundary info. since the node was constructed as a
19510  // boundary node
19511  bool build_node_as_boundary_node = false;
19512 
19513  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19514  {
19515  // Build the node as a boundary node
19516  build_node_as_boundary_node = true;
19517 
19518  // Try to get the node pointer in case that the node has been
19519  // already sent by the other processors
19520 
19521  // Get the number of initial shared boundaries to correct the
19522  // index of the shared boundary
19523  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
19524 
19525  // Add the found nodes in the container
19526  Vector<Node*> found_node_pt;
19527 
19528  // Now try to find the node in any of the other shared boundaries
19529  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
19530  {
19531  // We always check with the lower processor number. The
19532  // info. is only stored in one direction. More importantly,
19533  // this is done with the hope that the info. has been already
19534  // received from the other processor given that its info. was
19535  // processed before the current processor (iproc). NOTE that
19536  // it is not always the case that this info. has been received
19537  // from the other processors since it may have not require to
19538  // send the elements (and nodes) on the shared boundary with
19539  // the current processor (iproc).
19540  unsigned oproc1 = other_processor_1[i];
19541  unsigned oproc2 = other_processor_2[i];
19542  if (other_processor_1[i] > other_processor_2[i])
19543  {
19544  oproc1 = other_processor_2[i];
19545  oproc2 = other_processor_1[i];
19546  } // if (other_processor_1[i] > other_processor_2[i])
19547 
19548  // Re-compute the shared boundary id between the other
19549  // processors
19550  const unsigned shd_bnd_id =
19551  other_shared_boundaries[i] - initial_shd_bnd_id;
19552 
19553  // Read the index
19554  const unsigned index = other_indexes[i];
19555 
19556  // Check if there are nodes received from the other processor
19557  // and with the given shared boundary
19558  const unsigned n_nodes_on_other_processor =
19559  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].size();
19560 
19561  if (n_nodes_on_other_processor > 0)
19562  {
19563  // Check if we can find the index of the node in that
19564  // other processor and shared boundary id
19565  std::map<unsigned, Node*>::iterator it =
19566  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].
19567  find(index);
19568 
19569  // If the index exist then get the node pointer
19570  if (it!=
19571  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
19572  {
19573  // Mark the node as found
19574  found_node_in_other_shared_boundaries = true;
19575  // Get the node pointer
19576  Node* tmp_node_pt = (*it).second;
19577 
19578  // Push back the node pointer
19579  found_node_pt.push_back(tmp_node_pt);
19580 
19581  } // if (it!=
19582  // other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
19583 
19584  } // if (n_nodes_on_other_processor > 0)
19585 
19586  } // for (i < n_shd_bnd_with_other_procs_have_node)
19587 
19588  // If the node was found, then all their instances should be the
19589  // same but better check
19590  if (found_node_in_other_shared_boundaries)
19591  {
19592 #ifdef PARANOID
19593  const unsigned n_times_node_found = found_node_pt.size();
19594  for (unsigned j = 1; j < n_times_node_found; j++)
19595  {
19596  if (found_node_pt[j-1] != found_node_pt[j])
19597  {
19598  std::ostringstream error_message;
19599  error_message
19600  <<"The instances of the node that was found on\n"
19601  <<"shared boundaries with other processors (but not\n"
19602  <<"on shared boundaries with this processor) are not\n"
19603  <<"the same.\n"
19604  <<"These are the coordinates of the instances of the\n"
19605  <<"nodes:\n"
19606  <<"(" << found_node_pt[j-1]->x(0) << ", "
19607  << found_node_pt[j-1]->x(1) << ")\n"
19608  <<"(" << found_node_pt[j]->x(0) << ", "
19609  << found_node_pt[j]->x(1) << ")\n"
19610  <<"Dont be surprised if they are the same since the "
19611  << "node is\nrepeated.\n";
19612  throw OomphLibError(error_message.str(),
19613  OOMPH_CURRENT_FUNCTION,
19614  OOMPH_EXCEPTION_LOCATION);
19615 
19616  } // if (found_node_pt[j-1] != found_node_pt[j])
19617 
19618  } // for (j < ntimes_node_found)
19619 #endif // #ifdef PARANOID
19620 
19621  // Check if the node is a shared boundary node from the
19622  // current processor and the iproc processor, if that is the
19623  // case, and the node is also on a shared boundary with other
19624  // processor, then the pointer should be the same!!!
19625  if (is_node_on_shared_boundary == 1)
19626  {
19627  //const unsigned n_times_node_found = found_node_pt.size();
19628  // The pointer to the node is already assigned, it was
19629  // assigned when the node was found to be on a shared
19630  // boundary with the sending processor (iproc). Check that
19631  // any previous instances of the node have been copied
19632  // from the shared boundary, if that is not the case then
19633  // there is a problem
19634  if (found_node_pt[0] != new_nod_pt)
19635  {
19636  std::ostringstream error_message;
19637  error_message
19638  <<"The pointer of the node that was found to be on a\n"
19639  <<"shared boundary with other processor(s) and the pointer\n"
19640  <<"of the node on shared boundary with the receiver\n"
19641  <<"processor (iproc) are not the same. This means we have a\n"
19642  << "repeated node)\n"
19643  <<"The coordinates for the nodes are:\n"
19644  <<"(" << found_node_pt[0]->x(0) << ", "
19645  << found_node_pt[0]->x(1) << ")\n"
19646  <<"(" << new_nod_pt->x(0) << ", "
19647  << new_nod_pt->x(1) << ")\n"
19648  <<"Dont be surprised if they are the same since the "
19649  << "node is\nrepeated.\n";
19650  throw OomphLibError(error_message.str(),
19651  OOMPH_CURRENT_FUNCTION,
19652  OOMPH_EXCEPTION_LOCATION);
19653 
19654  } // if (found_node_pt[i] != new_nod_pt)
19655 
19656  } // if (is_node_on_shared_boundary == 1)
19657  else
19658  {
19659  // Take the first instance of the node in case that it was
19660  // found and is not on a shared boundary with the iproc
19661  // processor (the processor from which we are receiving
19662  // the info.)
19663  new_nod_pt = found_node_pt[0];
19664 
19665  }
19666 
19667  } // if (found_node_in_other_shared_boundaries)
19668 
19669  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
19670 
19671  // -----------------------------------------------------------------
19672  // Create the node or read the received info if the node is not on a
19673  // shared boundary with the iproc processor
19674  if (is_node_on_shared_boundary != 1)
19675  {
19676  // If the node is on a shared boundary with other processor we
19677  // need to read all the info. since the processor that sent the
19678  // info. did not know that the node is part of another shared
19679  // boundary
19680 
19681  // If the node is not on a shared boundary (with any processor),
19682  // or if this is the first time that the info. of the node is
19683  // received from any of the processors with which it has a shared
19684  // boundary, then we create the node
19685 
19686  // Is the node a boundary node or should it be build as a boundary
19687  // node because it is on a shared boundary with other processors
19688  if (node_on_original_boundaries==2 || build_node_as_boundary_node)
19689  {
19690  // Check if necessary to create the node, or if it has been
19691  // already found in shared boundaries with other processors
19692  if (!found_node_in_other_shared_boundaries)
19693  {
19694  // Construct a boundary node
19695  if (time_stepper_pt!=0)
19696  {
19697  new_nod_pt=new_el_pt->construct_boundary_node(node_index,
19698  time_stepper_pt);
19699  }
19700  else
19701  {
19702  new_nod_pt=new_el_pt->construct_boundary_node(node_index);
19703  }
19704 
19705  } // if (!found_node_in_other_shared_boundaries)
19706  else
19707  {
19708  // If the node was found then assign the node to the element
19709  new_el_pt->node_pt(node_index) = new_nod_pt;
19710 
19711  } // else if (!found_node_in_other_shared_boundaries)
19712 
19713  // Associate the node to the given boundaries
19714  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
19715  {
19716  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
19717  // Establish the boundary coordinates for the node
19718  Vector<double> zeta(1);
19719  zeta[0] = zeta_coordinates[i];
19720  new_nod_pt->set_coordinates_on_boundary(
19721  original_boundaries_node_is_on[i],zeta);
19722  }
19723 
19724  } // if (node is on an original boundary)
19725  else
19726  {
19727  // Check if necessary to create the node, or if it has been
19728  // already found in shared boundaries with other processors
19729  if (!found_node_in_other_shared_boundaries)
19730  {
19731  // Construct an ordinary (non-boundary) node
19732  if (time_stepper_pt!=0)
19733  {
19734  new_nod_pt=new_el_pt->construct_node(node_index, time_stepper_pt);
19735  }
19736  else
19737  {
19738  new_nod_pt=new_el_pt->construct_node(node_index);
19739  }
19740  } // if (!found_node_in_other_shared_boundaries)
19741  else
19742  {
19743  // If the node was found then assign the node to the element
19744  new_el_pt->node_pt(node_index) = new_nod_pt;
19745  } // else if (!found_node_in_other_shared_boundaries)
19746 
19747  } // else (the node is not a boundary node)
19748 
19749  // ... and gather all its information
19750 
19751  // If the node was found or not in other shared boundaries, this
19752  // is the first time the node is received from this processor
19753  // (iproc), therefore it is added to the vector of nodes received
19754  // from this processor (iproc)
19755  new_nodes_on_domain.push_back(new_nod_pt);
19756 
19757  // Check if necessary to state all the info. to the node if it has
19758  // been already found in shared boundaries with other processors
19759  if (!found_node_in_other_shared_boundaries)
19760  {
19761  // Add the node to the general node storage
19762  this->add_node_pt(new_nod_pt);
19763  } // if (!found_node_in_other_shared_boundaries)
19764 
19765  // Is the new constructed node Algebraic?
19766  AlgebraicNode* new_alg_nod_pt=dynamic_cast<AlgebraicNode*>
19767  (new_nod_pt);
19768 
19769  // If it is algebraic, its node update functions will
19770  // not yet have been set up properly
19771  if (new_alg_nod_pt!=0)
19772  {
19773  // The AlgebraicMesh is the external mesh
19774  AlgebraicMesh* alg_mesh_pt=dynamic_cast<AlgebraicMesh*>(this);
19775 
19776  /// The first entry of All_alg_nodal_info contains
19777  /// the default node update id
19778  /// e.g. for the quarter circle there are
19779  /// "Upper_left_box", "Lower right box" etc...
19780 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19781  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19782  << " Alg node update id "
19783  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19784  << std::endl;
19785 #endif
19786 
19787  unsigned update_id=Flat_packed_unsigneds
19788  [Counter_for_flat_packed_unsigneds++];
19789 
19790  Vector<double> ref_value;
19791 
19792  // The size of this vector is in the next entry
19793  // of All_alg_nodal_info
19794 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19795  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19796  << " Alg node # of ref values "
19797  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19798  << std::endl;
19799 #endif
19800  unsigned n_ref_val=Flat_packed_unsigneds
19801  [Counter_for_flat_packed_unsigneds++];
19802 
19803  // The reference values themselves are in
19804  // All_alg_ref_value
19805  ref_value.resize(n_ref_val);
19806  for (unsigned i_ref=0;i_ref<n_ref_val;i_ref++)
19807  {
19808  ref_value[i_ref]=Flat_packed_doubles
19809  [Counter_for_flat_packed_doubles++];
19810  }
19811 
19812  Vector<GeomObject*> geom_object_pt;
19813  /// again we need the size of this vector as it varies
19814  /// between meshes; we also need some indication
19815  /// as to which geometric object should be used...
19816 
19817  // The size of this vector is in the next entry
19818  // of All_alg_nodal_info
19819 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19820  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19821  << " Alg node # of geom objects "
19822  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19823  << std::endl;
19824 #endif
19825  unsigned n_geom_obj=Flat_packed_unsigneds
19826  [Counter_for_flat_packed_unsigneds++];
19827 
19828  // The remaining indices are in the rest of
19829  // All_alg_nodal_info
19830  geom_object_pt.resize(n_geom_obj);
19831  for (unsigned i_geom=0;i_geom<n_geom_obj;i_geom++)
19832  {
19833 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19834  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19835  << " Alg node: geom object index "
19836  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19837  << std::endl;
19838 #endif
19839  unsigned geom_index=Flat_packed_unsigneds
19840  [Counter_for_flat_packed_unsigneds++];
19841  // This index indicates which of the AlgebraicMesh's
19842  // stored geometric objects should be used
19843  // (0 is a null pointer; everything else should have
19844  // been filled in by the specific Mesh). If it
19845  // hasn't been filled in then the update_node_update
19846  // call should fix it
19847  geom_object_pt[i_geom]=alg_mesh_pt->
19848  geom_object_list_pt(geom_index);
19849  }
19850 
19851  // Check if necessary to state all the info. to the node if it has
19852  // been already found in shared boundaries with other processors
19853  if (!found_node_in_other_shared_boundaries)
19854  {
19855  /// For the received update_id, ref_value, geom_object
19856  /// call add_node_update_info
19857  new_alg_nod_pt->add_node_update_info
19858  (update_id,alg_mesh_pt,geom_object_pt,ref_value);
19859 
19860  /// Now call update_node_update
19861  alg_mesh_pt->update_node_update(new_alg_nod_pt);
19862 
19863  } // if (!found_node_in_other_shared_boundaries)
19864 
19865  } // if (new_alg_nod_pt!=0)
19866 
19867  // Check if necessary to state all the info. to the node if it has
19868  // been already found in shared boundaries with other processors
19869  if (!found_node_in_other_shared_boundaries)
19870  {
19871  // Is the node a MacroElementNodeUpdateNode?
19872  MacroElementNodeUpdateNode* macro_nod_pt=
19873  dynamic_cast<MacroElementNodeUpdateNode*>(new_nod_pt);
19874 
19875  if (macro_nod_pt!=0)
19876  {
19877  // Need to call set_node_update_info; this requires
19878  // a Vector<GeomObject*> (taken from the mesh)
19879  Vector<GeomObject*> geom_object_vector_pt;
19880 
19881  // Access the required geom objects from the
19882  // MacroElementNodeUpdateMesh
19883  MacroElementNodeUpdateMesh* macro_mesh_pt=
19884  dynamic_cast<MacroElementNodeUpdateMesh*>(this);
19885  geom_object_vector_pt=
19886  macro_mesh_pt->geom_object_vector_pt();
19887 
19888  // Get local coordinate of node in new element
19889  Vector<double> s_in_macro_node_update_element;
19890  new_el_pt->local_coordinate_of_node
19891  (node_index,s_in_macro_node_update_element);
19892 
19893  // Set node update info for this node
19894  macro_nod_pt->set_node_update_info
19895  (new_el_pt,s_in_macro_node_update_element,
19896  geom_object_vector_pt);
19897  }
19898 
19899  } // if (!found_node_in_other_shared_boundaries)
19900 
19901  // If there are additional values, resize the node
19902  unsigned n_new_val=new_nod_pt->nvalue();
19903 
19904  // Check if necessary to state all the info. to the node if it has
19905  // been already found in shared boundaries with other processors
19906  if (!found_node_in_other_shared_boundaries)
19907  {
19908  if (n_val>n_new_val)
19909  {
19910  // If it has been necessary to resize then it may be becuse
19911  // the node is on a FSI boundary, if that is the case we need
19912  // to set a map for these external values
19913 
19914  // Cast to a boundary node
19915  BoundaryNodeBase *bnod_pt =
19916  dynamic_cast<BoundaryNodeBase*>(new_nod_pt);
19917 
19918  // Create storage, if it doesn't already exist, for the map
19919  // that will contain the position of the first entry of
19920  // this face element's additional values,
19921  if(bnod_pt->index_of_first_value_assigned_by_face_element_pt()==0)
19922  {
19923  bnod_pt->index_of_first_value_assigned_by_face_element_pt()=
19924  new std::map<unsigned, unsigned>;
19925  }
19926 
19927  // Get pointer to the map
19928  std::map<unsigned, unsigned>* map_pt=
19929  bnod_pt->index_of_first_value_assigned_by_face_element_pt();
19930 
19931  // The id of the face to which this node belong in the bulk
19932  // element
19933  const unsigned id_face = 0;
19934  // We only resize the node values Vector if we haven't done it yet
19935  std::map<unsigned, unsigned>::const_iterator p=map_pt->find(id_face);
19936 
19937  // If this node hasn't been resized for current id
19938  if(p==map_pt->end())
19939  {
19940  // assign the face element id and the position of the
19941  //first entry to the boundary node
19942  (*map_pt)[id_face] = n_new_val;
19943 
19944  // resize the node vector of values
19945  new_nod_pt->resize(n_val);
19946  }
19947 
19948  } // if (n_val>n_new_val)
19949 
19950  } // if (!found_node_in_other_shared_boundaries)
19951 
19952  // Is the new node a SolidNode?
19953  SolidNode* solid_nod_pt=dynamic_cast<SolidNode*>(new_nod_pt);
19954  if (solid_nod_pt!=0)
19955  {
19956  unsigned n_solid_val=solid_nod_pt->variable_position_pt()->nvalue();
19957  for (unsigned i_val=0;i_val<n_solid_val;i_val++)
19958  {
19959  for (unsigned t=0;t<n_prev;t++)
19960  {
19961  double read_data =
19962  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
19963 
19964  // Check if necessary to state all the info. to the node if it has
19965  // been already found in shared boundaries with other processors
19966  if (!found_node_in_other_shared_boundaries)
19967  {
19968  solid_nod_pt->variable_position_pt()->
19969  set_value(t, i_val, read_data);
19970  } // if (!found_node_in_other_shared_boundaries)
19971 
19972  }
19973 
19974  }
19975 
19976 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION
19977  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
19978  << " Number of values solid node: "
19979  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
19980  << std::endl;
19981 #endif
19982  const unsigned nvalues_solid_node =
19983  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
19984  Vector<double> values_solid_node(nvalues_solid_node);
19985  for (unsigned i = 0; i < nvalues_solid_node; i++)
19986  {
19987  values_solid_node[i] =
19988  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
19989  }
19990 
19991  // Check if necessary to state all the info. to the node if it has
19992  // been already found in shared boundaries with other processors
19993  if (!found_node_in_other_shared_boundaries)
19994  {
19995  unsigned index = 0;
19996  solid_nod_pt->read_values_from_vector(values_solid_node, index);
19997  }
19998 
19999  }
20000 
20001  // Get copied history values
20002  // unsigned n_val=new_nod_pt->nvalue();
20003  for (unsigned i_val=0;i_val<n_val;i_val++)
20004  {
20005  for (unsigned t=0;t<n_prev;t++)
20006  {
20007  double read_data =
20008  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
20009 
20010  // Check if necessary to state all the info. to the node if it
20011  // has been already found in shared boundaries with other
20012  // processors
20013  if (!found_node_in_other_shared_boundaries)
20014  {
20015  new_nod_pt->set_value(t, i_val, read_data);
20016  } // if (!found_node_in_other_shared_boundaries)
20017 
20018  }
20019 
20020  }
20021 
20022  // Get copied history values for positions
20023  unsigned n_dim=new_nod_pt->ndim();
20024  for (unsigned idim=0;idim<n_dim;idim++)
20025  {
20026  for (unsigned t=0;t<n_prev;t++)
20027  {
20028  double read_data =
20029  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
20030 
20031  // Check if necessary to state all the info. to the node if it
20032  // has been already found in shared boundaries with other
20033  // processors
20034  if (!found_node_in_other_shared_boundaries)
20035  {
20036  // Copy to coordinate
20037  new_nod_pt->x(t,idim) = read_data;
20038 
20039  } // if (!found_node_in_other_shared_boundaries)
20040  }
20041  }
20042 
20043  } // if (is_node_on_shared_boundary != 1)
20044 
20045  // If the node was not found in other shared boundaries (possibly
20046  // because it is the first time the node has been sent) then copy
20047  // the node to the shared boundaries where it should be, use the
20048  // special container for this cases
20049  if (n_shd_bnd_with_other_procs_have_node > 0 && // The node is on
20050  // shared
20051  // boundaries with
20052  // other processors
20053  !found_node_in_other_shared_boundaries) // The node has not
20054  // been previously
20055  // set as
20056  // shared with
20057  // other processors
20058  // (first time)
20059  {
20060  // Update the node pointer in all the (references) of the node
20061  this->update_other_proc_shd_bnd_node_helper(new_nod_pt,
20062  other_proc_shd_bnd_node_pt,
20063  other_processor_1,
20064  other_processor_2,
20065  other_shared_boundaries,
20066  other_indexes,
20067  global_node_names,
20068  node_name_to_global_index,
20069  global_shared_node_pt);
20070 
20071  } // if (!found_node_in_other_shared_boundaries)
20072 
20073  }
20074 
20075 //========start of update_other_proc_shd_bnd_node_helper=================
20076 //Helper function that assigns/updates the references to the node so
20077 //that it can be found with any other reference
20078 //========================================================================
20079 template<class ELEMENT>
20082 (Node* &new_node_pt,
20083  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
20084  &other_proc_shd_bnd_node_pt,
20085  Vector<unsigned> &other_processor_1,
20086  Vector<unsigned> &other_processor_2,
20087  Vector<unsigned> &other_shared_boundaries,
20088  Vector<unsigned> &other_indexes,
20089  Vector<Vector<Vector<unsigned> > > &global_node_names,
20090  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
20091  Vector<Node*> &global_shared_node_pt)
20092 {
20093  // Get the number of initial shared boundaries to correct the index
20094  // of the shared boundary
20095  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
20096 
20097 #ifdef PARANOID
20098  // Get the number of instances of the node on other shared
20099  // boundaries with other processors
20100  const unsigned n_data = other_processor_1.size();
20101 #endif // #ifdef PARANOID
20102 
20103  // Create the first node name
20104  Vector<unsigned> node_name(4);
20105  node_name[0] = other_processor_1[0];
20106  node_name[1] = other_processor_2[0];
20107  node_name[2] = other_shared_boundaries[0];
20108  node_name[3] = other_indexes[0];
20109 
20110 #ifdef PARANOID
20111  // Get the global node index, and all the names of the node
20112  std::map<Vector<unsigned>, unsigned>::iterator it =
20113  node_name_to_global_index.find(node_name);
20114  if (it==node_name_to_global_index.end())
20115  {
20116  std::ostringstream error_stream;
20117  error_stream
20118  <<"The node name does not exist in the global node names\n"
20119  <<"This is the name of the node\n"
20120  << "Name: iproc, jproc, ishd_bnd, idx\n"
20121  <<"Name: " << node_name[0] <<", " << node_name[1] <<", "
20122  << node_name[2] <<", " << node_name[3] <<"\n";
20123  throw OomphLibError(error_stream.str(),
20124  OOMPH_CURRENT_FUNCTION,
20125  OOMPH_EXCEPTION_LOCATION);
20126  } // if (it!=node_name_to_global_index.end())
20127 #endif // #ifdef PARANOID
20128 
20129  // Get the global node index
20130  const unsigned iglobal_node = node_name_to_global_index[node_name];
20131  // Add the node to the global shared node container
20132  global_shared_node_pt[iglobal_node] = new_node_pt;
20133  // Get the names
20134  Vector<Vector<unsigned> > inode_names = global_node_names[iglobal_node];
20135  // Get the number of names of the node
20136  const unsigned n_names = inode_names.size();
20137 
20138 #ifdef PARANOID
20139  // Check that the received names of the node are part of the global
20140  // node names
20141  unsigned n_found_node_names_on_global_node_name = 0;
20142  // loop over the input node names
20143  for (unsigned j = 0; j < n_data; j++)
20144  {
20145  // loop over the inode_names
20146  for (unsigned k = 0; k < n_names; k++)
20147  {
20148  // Is this input name part of the global node names?
20149  if (inode_names[k][0] == other_processor_1[j] &&
20150  inode_names[k][1] == other_processor_2[j] &&
20151  inode_names[k][2] == other_shared_boundaries[j] &&
20152  inode_names[k][3] == other_indexes[j])
20153  {
20154  // Increase the number of found input node names in the
20155  // global node names
20156  n_found_node_names_on_global_node_name++;
20157  }
20158 
20159  } // for (k < n_names)
20160 
20161  } // for (j < n_data)
20162 
20163  // Were all the input node names found on the global node names?
20164  if (n_found_node_names_on_global_node_name != n_data)
20165  {
20166  std::ostringstream error_stream;
20167  error_stream
20168  <<"Not all the node names of the current node were found on the\n"
20169  <<"global node names. This happened when adding the node pointer\n"
20170  <<"to the data structure that keeps tracks of nodes on shared\n"
20171  <<"boundaries with other processors\n\n"
20172  << "These are the names of the current node\n"
20173  << "Name k: iproc, jproc, ishd_bnd, idx\n";
20174  for (unsigned j = 0; j < n_data; j++)
20175  {
20176  error_stream<<"Name("<<j<<"): "
20177  <<other_processor_1[j] <<", "
20178  <<other_processor_2[j] <<", "
20179  <<other_shared_boundaries[j] <<", "
20180  <<other_indexes[j] <<"\n";
20181  }
20182 
20183  error_stream
20184  << "\n\nThese are the names of the global node\n"
20185  << "Name k: iproc, jproc, ishd_bnd, idx\n";
20186  for (unsigned k = 0; k < n_names; k++)
20187  {
20188  error_stream<<"Name("<<k<<"): "
20189  <<inode_names[k][0] <<", "
20190  <<inode_names[k][1] <<", "
20191  <<inode_names[k][2] <<", "
20192  <<inode_names[k][3] <<"\n";
20193  }
20194 
20195  throw OomphLibError(error_stream.str(),
20196  OOMPH_CURRENT_FUNCTION,
20197  OOMPH_EXCEPTION_LOCATION);
20198  }
20199 #endif // #ifdef PARANOID
20200 
20201  // Set the node pointer in all of its names
20202  for (unsigned j = 0; j < n_names; j++)
20203  {
20204  // Get the j-th node name
20205  const unsigned iproc = inode_names[j][0];
20206  const unsigned jproc = inode_names[j][1];
20207  const unsigned ishd_bnd = inode_names[j][2] - initial_shd_bnd_id;
20208  const unsigned index = inode_names[j][3];
20209 
20210  // The info. is stored only in one direction
20211  // Get the smallest processor number
20212  if (iproc < jproc)
20213  {
20214  other_proc_shd_bnd_node_pt[iproc][jproc][ishd_bnd][index]
20215  = new_node_pt;
20216  }
20217  else
20218  {
20219  other_proc_shd_bnd_node_pt[jproc][iproc][ishd_bnd][index]
20220  = new_node_pt;
20221  }
20222 
20223  } // for (j < n_names)
20224 
20225 }
20226 
20227  // *********************************************************************
20228  // End communication functions
20229  // *********************************************************************
20230 
20231  // *********************************************************************
20232  // BEGIN: Methods to perform load balance
20233  // *********************************************************************
20234 
20235  //======================================================================
20236  /// \short Performs the load balancing for unstructured meshes, the
20237  /// load balancing strategy is based on mesh migration
20238  //======================================================================
20239  template <class ELEMENT>
20241  load_balance(const Vector<unsigned>&
20242  target_domain_for_local_non_halo_element)
20243  {
20244  oomph_info << "Load balance (unstructured mesh) [BEGIN]" << std::endl;
20245 
20246  // This method can only be called when the mesh has been already
20247  // distributed
20248  if (!this->is_mesh_distributed())
20249  {
20250  std::ostringstream warning_message;
20251  warning_message
20252  << "\n===============================================================\n"
20253  << "The load balancing can only be performed in distributed meshes,\n"
20254  << "your mesh has not been distributed.\n"
20255  << "===============================================================\n\n";
20256  OomphLibWarning(warning_message.str(),
20257  OOMPH_CURRENT_FUNCTION,
20258  OOMPH_EXCEPTION_LOCATION);
20259  // Return
20260  return;
20261  }
20262 
20263  // Get the number of processors
20264  const unsigned nproc = this->communicator_pt()->nproc();
20265  // Get the rank of the current processors
20266  const unsigned my_rank = this->communicator_pt()->my_rank();
20267 
20268  // Check that there are at least two processors
20269  if (nproc == 1)
20270  {
20271  std::ostringstream warning_message;
20272  warning_message
20273  << "\n===============================================================\n"
20274  << "The load balancing can only be performed when there are at least\n"
20275  << "two procesors, the current number of processors is one.\n"
20276  << "===============================================================\n\n";
20277  OomphLibWarning(warning_message.str(),
20278  OOMPH_CURRENT_FUNCTION,
20279  OOMPH_EXCEPTION_LOCATION);
20280  // Return
20281  return;
20282  }
20283 
20284  // Get the time before load balance
20285  double t_start_overall_load_balance=0.0;
20286  if (Print_timings_level_load_balance>1)
20287  {
20288  t_start_overall_load_balance=TimingHelpers::timer();
20289  }
20290 
20291  // Get the number of elements in the mesh before load balance
20292  const unsigned nelement_before_load_balance = this->nelement();
20293 
20294 #ifdef PARANOID
20295  // The number of elements in the mesh and the number of target
20296  // domains for the local non halo elements in the mesh should match
20297  if (nnon_halo_element() !=
20298  target_domain_for_local_non_halo_element.size())
20299  {
20300  std::ostringstream error_message;
20301  error_message
20302  << "The number of non halo elements in the current mesh ("
20303  << nnon_halo_element() << ") and the number\n"
20304  << "of target areas for the local non halo elements ("
20305  << target_domain_for_local_non_halo_element.size()
20306  << ") is different\n\n";
20307  throw OomphLibError(error_message.str(),
20308  OOMPH_CURRENT_FUNCTION,
20309  OOMPH_EXCEPTION_LOCATION);
20310  }
20311 #endif
20312 
20313  // Backup pointers to elements in this mesh
20314  Vector<FiniteElement*> backed_up_ele_pt(nelement_before_load_balance);
20315  for (unsigned e = 0; e < nelement_before_load_balance; e++)
20316  {
20317  backed_up_ele_pt[e] = this->finite_element_pt(e);
20318  }
20319 
20320  // =====================================================================
20321  // BEGIN: GET THE DOMAINS FOR THE HALO ELEMENTS
20322  // =====================================================================
20323 
20324  // Get the time to get the domains of halo elements
20325  double tt_start_get_domains_halo_elements=0.0;
20326  if (Print_timings_level_load_balance>1)
20327  {
20328  tt_start_get_domains_halo_elements=TimingHelpers::timer();
20329  }
20330 
20331  // Get the new domains for the halo elements
20332 
20333  // Send the new domains for the current haloed elements, and receive
20334  // the new domains for the current halo elements
20335  // -- 1) On the current processor get the new domains for the
20336  // haloed elements
20337  // -- 2) Then send this info. to all the processor that have a
20338  // halo copy of the element
20339 
20340  // The storing for the new domains of the haloed elements (sent to
20341  // other processors)
20342  Vector<Vector<unsigned> > new_domains_haloed_elements(nproc);
20343  // The storing for the new domains of the halo elements (received
20344  // from other processors)
20345  Vector<Vector<unsigned> > new_domains_halo_elements(nproc);
20346 
20347  // First resize the containers by getting the current number of
20348  // halo/haloed elements within each processor
20349  for (unsigned iproc = 0; iproc < nproc; iproc++)
20350  {
20351  // There are no halo/haloed elements with myself (my_rank
20352  // processor)
20353  if (iproc != my_rank)
20354  {
20355  // Get the number of halo elements with iproc processor
20356  const unsigned n_halo_iproc = this->nroot_halo_element(iproc);
20357  // Resize the container
20358  new_domains_halo_elements[iproc].resize(n_halo_iproc);
20359 
20360  // Get the number of haloed elements with iproc processor
20361  const unsigned n_haloed_iproc = this->nroot_haloed_element(iproc);
20362  // Resize the container
20363  new_domains_haloed_elements[iproc].resize(n_haloed_iproc);
20364  } // if (iproc != my_rank)
20365  } // for (iproc < nproc)
20366 
20367 #ifdef PARANOID
20368  // Count the number of found haloed elements
20369  Vector<unsigned> counter_for_found_haloed_elements(nproc, 0);
20370 #endif
20371 
20372  // Go through all the haloed elements and find their new domain
20373 
20374  // Get the haloed elements with in each processor and check if the
20375  // element is haloed with the processor
20376  for (unsigned iproc = 0; iproc < nproc; iproc++)
20377  {
20378  // There are no halo/haloed elements with myself (my_rank
20379  // processor)
20380  if (iproc != my_rank)
20381  {
20382  // Get the number of haloed elements with iproc processor
20383  const unsigned n_haloed_iproc = this->nroot_haloed_element(iproc);
20384 
20385  // Loop over the haloed elements
20386  for (unsigned ihd = 0; ihd < n_haloed_iproc; ihd++)
20387  {
20388  // Get the ihd-th haloed element with "iproc" processor
20389  GeneralisedElement* haloed_ele_pt =
20390  this->root_haloed_element_pt(iproc, ihd);
20391 
20392  // The counter for the nonhalo elements
20393  unsigned nh_count4 = 0;
20394  // Find the element in the general elements container
20395  for (unsigned e = 0; e < nelement_before_load_balance; e++)
20396  {
20397  // Get the e-th element
20398  GeneralisedElement* ele_pt = this->element_pt(e);
20399  // Check if the element is a nonhalo element
20400  if (!ele_pt->is_halo())
20401  {
20402  // Increase the counter for nonhalo elements, in case the
20403  // haloed element is found get the (nh_count4-1) position
20404  // in the target domains vector
20405  nh_count4++;
20406 
20407  if (ele_pt == haloed_ele_pt)
20408  {
20409  // Get the new domain for this element
20410  const unsigned element_domain =
20411  target_domain_for_local_non_halo_element[nh_count4-1];
20412  // Here decrease the counter ---------------------^
20413 
20414  // Set the new domain for the haloed element in the
20415  // special container
20416  new_domains_haloed_elements[iproc][ihd] = element_domain;
20417 #ifdef PARANOID
20418  // Increase the counter
20419  counter_for_found_haloed_elements[iproc]++;
20420 #endif
20421  // ... and break the "for" with the general
20422  // elements. Continue with the next haloed element
20423  break;
20424 
20425  } // if (ele_pt == haloed_ele_pt))
20426 
20427  } // if (!ele_pt->is_halo())
20428 
20429  } // for (e < nelement_before_load_balance)
20430 
20431  } // for (ihd < n_haloed_iproc)
20432 
20433  } // if (iproc != my_rank)
20434 
20435  } // for (iproc < nproc)
20436 
20437 #ifdef PARANOID
20438  // Check that all the haloed elements with all processors have been
20439  // found
20440  for (unsigned iproc = 0; iproc < nproc; iproc++)
20441  {
20442  // There are no halo/haloed elements with myself (my_rank
20443  // processor)
20444  if (iproc != my_rank)
20445  {
20446  // Get the number of haloed elements with "iproc" processor
20447  const unsigned n_haloed_iproc = this->nroot_haloed_element(iproc);
20448 
20449  // Compare the number of found haloed elements with the current
20450  // number of haloed elements
20451  if (n_haloed_iproc != counter_for_found_haloed_elements[iproc])
20452  {
20453  std::ostringstream error_message;
20454  error_message
20455  << "The independent counting of found haloed elements ("
20456  << counter_for_found_haloed_elements[iproc] << ") with processor ("
20457  << iproc << ") is not equal to the number of haloed elements ("
20458  << n_haloed_iproc << ") with processor (" << iproc << ")\n";
20459  throw OomphLibError(error_message.str(),
20460  OOMPH_CURRENT_FUNCTION,
20461  OOMPH_EXCEPTION_LOCATION);
20462  } // if (nhaloed_iproc == counter_for_found_haloed_elements[iproc])
20463 
20464  } // if (iproc != my_rank)
20465 
20466  } // for (iproc < nproc)
20467 #endif
20468 
20469  // Now we have the new domains for the haloed elements
20470 
20471  // Send this info. to the processor with a halo copy of the haloed
20472  // elements and set the new domains in the halo copies
20473 
20474  // First put all the info. in a flat package array
20475  Vector<unsigned> new_domains_haloed_flat_unsigned;
20476  // Put in a vector the number of haloed elements within each
20477  // processor
20478  Vector<int> nhaloed_elements_with_iproc(nproc);
20479  for (unsigned iproc = 0; iproc < nproc; iproc++)
20480  {
20481  // There are no halo/haloed elements with myself (my_rank
20482  // processor)
20483  if (iproc != my_rank)
20484  {
20485  // Get the number of haloed elements with "iproc" processor
20486  const unsigned n_haloed_ele_iproc = this->nroot_haloed_element(iproc);
20487  // Copy the number of haloed elements with "iproc" processor
20488  nhaloed_elements_with_iproc[iproc] = n_haloed_ele_iproc;
20489  // Copy the new domains of the haloed elements in the flat
20490  // package
20491  for (unsigned i = 0; i < n_haloed_ele_iproc; i++)
20492  {
20493  new_domains_haloed_flat_unsigned.push_back(
20494  new_domains_haloed_elements[iproc][i]);
20495  } // for (i < n_haloed_ele_iproc)
20496 
20497  } // if (iproc != my_rank)
20498 
20499  } // for (iproc < nproc)
20500 
20501  // The offsets of the flat package within each processor
20502  Vector<int> offset_haloed_elements_with_iproc(nproc);
20503  offset_haloed_elements_with_iproc[0] = 0;
20504  for (unsigned ip = 1; ip < nproc; ip++)
20505  {
20506  // Compute the offset to send the values to each processor
20507  offset_haloed_elements_with_iproc[ip] =
20508  offset_haloed_elements_with_iproc[ip-1] +
20509  nhaloed_elements_with_iproc[ip-1];
20510  } // for (ip < nproc)
20511 
20512  // Prepare to receive the data
20513 
20514  // Compute the number of data (halo elements) to receive from each
20515  // processor and the displacements within each processor
20516 
20517  // Counter for the total number of halo elements within all processors
20518  unsigned counter_halo_ele_with_all_procs = 0;
20519 
20520  // Put in a vector the number of halo elements expected to receive
20521  // from each processor
20522  Vector<int> nhalo_elements_with_iproc(nproc);
20523  // Compute the number of total halo elements of (my_rank) this
20524  // processor with all other processors
20525  for (unsigned iproc = 0; iproc < nproc; iproc++)
20526  {
20527  // There are no halo/haloed elements with myself (my_rank
20528  // processor)
20529  if (iproc != my_rank)
20530  {
20531  // Get the number of halo elements with "iproc" processor
20532  const unsigned n_halo_ele_iproc = this->nroot_halo_element(iproc);
20533  // Copy the number of halo elements with "iproc" processor
20534  nhalo_elements_with_iproc[iproc] = n_halo_ele_iproc;
20535  // Add the number of elements with this processor
20536  counter_halo_ele_with_all_procs+= n_halo_ele_iproc;
20537  } // if (iproc != my_rank)
20538 
20539  } // for (iproc < nproc)
20540 
20541  // The offsets of the flat package within each processor
20542  Vector<int> offset_halo_elements_with_iproc(nproc);
20543  offset_halo_elements_with_iproc[0] = 0;
20544  for (unsigned ip = 1; ip < nproc; ip++)
20545  {
20546  // Compute the offset to receive the values from each processor
20547  offset_halo_elements_with_iproc[ip] =
20548  offset_halo_elements_with_iproc[ip-1] +
20549  nhalo_elements_with_iproc[ip-1];
20550  } // for (ip < nproc)
20551 
20552  // The flat container to receive the new domains of the halo
20553  // elements in the current processor
20554 
20555  // The flat package where all the info. will be gather from the
20556  // other processors (the halo flat package)
20557  Vector<unsigned>
20558  new_domains_halo_flat_unsigned(counter_halo_ele_with_all_procs);
20559 
20560  // Perform the sending and receiving of information to and from all
20561  // processors
20562  MPI_Alltoallv(&new_domains_haloed_flat_unsigned[0], // void *sendbuf
20563  &nhaloed_elements_with_iproc[0], // int *sendcnts
20564  &offset_haloed_elements_with_iproc[0], // int *sdispls
20565  MPI_UNSIGNED, // MPI_Datatype sendtype
20566  &new_domains_halo_flat_unsigned[0], // void *recvbuf
20567  &nhalo_elements_with_iproc[0], // int *recvcnts
20568  &offset_halo_elements_with_iproc[0], // int *rdispls
20569  MPI_UNSIGNED, // MPI_Datatype recvtype
20570  this->communicator_pt()->mpi_comm()); // MPI_Comm comm
20571 
20572  // Once received the new domains for the halo elements, copy the
20573  // domains back to an easier to handle container (from the flat
20574  // package to the one with the different halo elements domains
20575  // within each processor)
20576  unsigned counter_new_domains_halo_ele = 0;
20577  for (unsigned iproc = 0; iproc < nproc; iproc++)
20578  {
20579  // There are no halo/haloed elements with myself (my_rank
20580  // processor)
20581  if (iproc != my_rank)
20582  {
20583  // Get the number of halo elements with "iproc"
20584  const unsigned ntmp_halo_elements_with_iproc =
20585  nhalo_elements_with_iproc[iproc];
20586  // Loop over the number of halo elements within "iproc" and copy
20587  // the elements from the flat package
20588  for (unsigned i = 0; i < ntmp_halo_elements_with_iproc; i++)
20589  {
20590  // Copy the new domain of the halo elements from the flat
20591  // package to an easier to use container
20592  new_domains_halo_elements[iproc][i] =
20593  new_domains_halo_flat_unsigned[counter_new_domains_halo_ele++];
20594  }
20595  } // if (iproc != my_rank)
20596  } // for (iproc < nproc)
20597 
20598  // The time to get domains of halo elements
20599  if (Print_timings_level_load_balance>1)
20600  {
20601  oomph_info << "CPU for getting domains halo elements (load balance) [1]: "
20602  <<TimingHelpers::timer()-tt_start_get_domains_halo_elements
20603  << std::endl;
20604  }
20605 
20606  // =====================================================================
20607  // END: GET THE DOMAINS FOR THE HALO ELEMENTS
20608  // =====================================================================
20609 
20610  // =====================================================================
20611  // BEGIN: CREATE FINITE ELEMENT LOCAL VERSIONS OF THE HALO(ED)
20612  // ELEMENTS
20613  // =====================================================================
20614 
20615  // Get the time to get FiniteElement versions from Generalised
20616  // halo(ed) elements
20617  double tt_start_get_fe_version_from_ge_halo_ed=0.0;
20618  if (Print_timings_level_load_balance>1)
20619  {
20620  tt_start_get_fe_version_from_ge_halo_ed=TimingHelpers::timer();
20621  }
20622 
20623  // The finite element storage for the halo elements
20624  Vector<Vector<FiniteElement*> > f_halo_element_pt(nproc);
20625  // The finite element storage for the haloed elements
20626  Vector<Vector<FiniteElement*> > f_haloed_element_pt(nproc);
20627  // Loop over the processors
20628  for (unsigned iproc = 0; iproc < nproc; iproc++)
20629  {
20630  // There are no halo(ed) elements with myself
20631  if (iproc != my_rank)
20632  {
20633  // Get the number of halo elements with the "iproc" processor
20634  const unsigned nhalo_ele_iproc = this->nroot_halo_element(iproc);
20635  // Get the halo elements with the "iproc" processor
20636  Vector<GeneralisedElement*> halo_element_pt_iproc =
20637  this->root_halo_element_pt(iproc);
20638  // Resize the finite element container
20639  f_halo_element_pt[iproc].resize(nhalo_ele_iproc);
20640  // Loop over the halo elements
20641  for (unsigned ih = 0; ih < nhalo_ele_iproc; ih++)
20642  {
20643  // Get the finite element
20644  FiniteElement* ele_pt =
20645  dynamic_cast<FiniteElement*>(halo_element_pt_iproc[ih]);
20646  // Store the finite element version of the element
20647  f_halo_element_pt[iproc][ih] = ele_pt;
20648  } // for (ih < nhalo_ele_iproc)
20649 
20650  // Get the number of haloed elements with the "iproc" processor
20651  const unsigned nhaloed_ele_iproc = this->nroot_haloed_element(iproc);
20652  // Get the haloed elements with the "iproc" processor
20653  Vector<GeneralisedElement*> haloed_element_pt_iproc =
20654  this->root_haloed_element_pt(iproc);
20655  // Resize the finite element container
20656  f_haloed_element_pt[iproc].resize(nhaloed_ele_iproc);
20657  // Loop over the haloed elements
20658  for (unsigned ihd = 0; ihd < nhaloed_ele_iproc; ihd++)
20659  {
20660  // Get the finite element
20661  FiniteElement* ele_pt =
20662  dynamic_cast<FiniteElement*>(haloed_element_pt_iproc[ihd]);
20663  // Store the finite element version of the element
20664  f_haloed_element_pt[iproc][ihd] = ele_pt;
20665  } // for (ih < nhaloed_ele_iproc)
20666 
20667  } // if (iproc != my_rank)
20668 
20669  } // for (iproc < nproc)
20670 
20671  // The time to get FiniteElement versions from Generalised halo(ed)
20672  // elements
20673  if (Print_timings_level_load_balance>1)
20674  {
20675  oomph_info << "CPU for getting finite element versions from generalised halo(ed) elements (load balance) [2]: "
20676  <<TimingHelpers::timer()-tt_start_get_fe_version_from_ge_halo_ed
20677  << std::endl;
20678  }
20679 
20680  // =====================================================================
20681  // END: CREATE FINITE ELEMENT LOCAL VERSIONS OF THE HALO(ED)
20682  // ELEMENTS
20683  // =====================================================================
20684 
20685  // =====================================================================
20686  // BEGIN: 1) PREPARE THE ELEMENTS THAT WILL BE SENT TO OTHER PROCESSORS
20687  // ---- HALO ELEMENTS ARE NOT CONSIDERED FOR SENDING
20688  // 2) ASSOCIATE THE NODES WITH THE NEW DOMAIN OF THE ELEMENTS
20689  // ---- THE SAME IS PERFORMED FOR NODES IN HALO ELEMENTS
20690  // =====================================================================
20691 
20692  // Get the time to prepare elements to send to other processors
20693  double tt_start_prepare_element_to_send=0.0;
20694  if (Print_timings_level_load_balance>1)
20695  {
20696  tt_start_prepare_element_to_send=TimingHelpers::timer();
20697  }
20698 
20699  // Store the elements that will be sent to other processors
20700  Vector<Vector<FiniteElement*> > elements_to_send_pt(nproc);
20701 
20702  // Associate the nodes of each element with the processor the
20703  // element will live on
20704  std::map<Data*,std::set<unsigned> >
20705  processors_associated_with_data_before_load_balance;
20706 
20707  // Compute the elements that will be sent to other processor and
20708  // associate the nodes with the processor the element will live on
20709  unsigned nh_count3 = 0;
20710  for (unsigned e = 0; e < nelement_before_load_balance; e++)
20711  {
20712  // Get the element
20713  FiniteElement *ele_pt = this->finite_element_pt(e);
20714  // Only work with nonhalo elements
20715  if (!(ele_pt->is_halo()))
20716  {
20717  // Get the new domain for the elment
20718  const unsigned element_domain =
20719  target_domain_for_local_non_halo_element[nh_count3++];
20720 
20721  // Include the element in the corresponding vector
20722  elements_to_send_pt[element_domain].push_back(ele_pt);
20723 
20724  // Get the number of nodes on the element
20725  const unsigned n_nodes = ele_pt->nnode();
20726  // Loop over the nodes
20727  for (unsigned j = 0; j < n_nodes; j++)
20728  {
20729  // Get each node of the element
20730  Node* node_pt = ele_pt->node_pt(j);
20731  // ... and associate it with element domains
20732  processors_associated_with_data_before_load_balance[node_pt].
20733  insert(element_domain);
20734 
20735  } // for (j < n_nodes)
20736 
20737  } // if (!(ele_pt->is_halo()))
20738 
20739  } // for (e < nelement_before_load_balance)
20740 
20741  // ... do the same for the halo elements (but do not add them to the
20742  // sending container since only the processor with the haloed
20743  // counterparts is in charge of that). Associate the nodes of the
20744  // halo elements with the processor they will live on
20745  for (unsigned iproc = 0; iproc < nproc; iproc++)
20746  {
20747  // There is no halo elements with myself
20748  if (iproc != my_rank)
20749  {
20750  // Get the number of halo elements with the "iproc" processor
20751  const unsigned n_halo_ele_iproc = this->nroot_halo_element(iproc);
20752  // Get the halo elements with the "iproc" processor
20753  Vector<GeneralisedElement*> halo_element_pt_iproc =
20754  this->root_halo_element_pt(iproc);
20755  // Loop over the halo elements with iproc
20756  for (unsigned ih = 0; ih < n_halo_ele_iproc; ih++)
20757  {
20758  // Get the new domain for the halo element
20759  const unsigned element_domain =
20760  new_domains_halo_elements[iproc][ih];
20761 
20762  // Get the finite element
20763  FiniteElement* ele_pt =
20764  dynamic_cast<FiniteElement*>(halo_element_pt_iproc[ih]);
20765 
20766  // Get the number of nodes on the halo element
20767  const unsigned n_nodes = ele_pt->nnode();
20768  // Loop over the nodes
20769  for (unsigned j = 0; j < n_nodes; j++)
20770  {
20771  // Get each node of the halo element
20772  Node* node_pt = ele_pt->node_pt(j);
20773 
20774  // ... and associate it with element domains
20775  processors_associated_with_data_before_load_balance[node_pt].
20776  insert(element_domain);
20777 
20778  } // for (j < n_nodes)
20779 
20780  } // for (ih < nhalo_ele_iproc)
20781 
20782  } // if (iproc != my_rank)
20783 
20784  } // for (iproc < nproc)
20785 
20786  // The time to prepare elements to send to other processors
20787  if (Print_timings_level_load_balance>1)
20788  {
20789  oomph_info << "CPU for preparing elements to send to other processors (load balance) [3]: "
20790  <<TimingHelpers::timer()-tt_start_prepare_element_to_send
20791  << std::endl;
20792  }
20793 
20794  // Now all the nodes are associated with the processor where the
20795  // element will live on. This is performed for the nonhalo and halo
20796  // elements
20797 
20798  // =====================================================================
20799  // END: 1) PREPARE THE ELEMENTS THAT WILL BE SENT TO OTHER PROCESSORS
20800  // ---- HALO ELEMENTS ARE NOT CONSIDERED FOR SENDING
20801  // 2) ASSOCIATE THE NODES WITH THE NEW DOMAIN OF THE ELEMENTS
20802  // ---- THE SAME IS PERFORMED FOR NODES IN HALO ELEMENTS
20803  // =====================================================================
20804 
20805  // =====================================================================
20806  // BEGIN: COMPUTE THE NEW LOCAL HALO ELEMENTS OF ALL PROCESSORS IN THE
20807  // CURRENT PROCESSOR
20808  // ----- FOR NONHALO ELEMENTS AND FOR HALO ELEMENTS
20809  // =====================================================================
20810 
20811  // Get the time to compute new local halo elements within all
20812  // processors
20813  double tt_start_compute_new_local_halo_elements=0.0;
20814  if (Print_timings_level_load_balance>1)
20815  {
20816  tt_start_compute_new_local_halo_elements=TimingHelpers::timer();
20817  }
20818 
20819  // Before sending the elements across compute the new local
20820  // halo/haloed elements of each processor. Each processor could have
20821  // elements that will be part of the new halo/haloed elements of
20822  // another processors, then these processors need to compute the
20823  // relations that may happen among these other processors
20824 
20825  // Example:
20826  // Processor 1 may have elements that will be sent to processor 3
20827  // and 4. These processors need to know about the new halo elements
20828  // betweeen them but at this moment only processor 1 can compute that
20829  // info., since it is the only one that currently has that info.
20830 
20831  // Store the new local-halo elements of each processor, the HALOED
20832  // elements are also stored in the container, only needs to INVERT
20833  // the indexes. For example, the HALO elements of processor 2 with
20834  // processor 3 are stored in new_local_halo_element_pt[2][3], and
20835  // the HALOED elements of processor 2 with processor 3 are stored in
20836  // new_local_halo_element_pt[3][2]. Notice that these are also the
20837  // halo elements of processor 3 with 2
20838 
20839  // How to identify the new local halo/haloed element: 1) Loop over
20840  // the element; 2) Only work with nonhalo elements; 3) If the
20841  // element is not assigned to the current processor (iproc) then
20842  // check; 4) Is one of its nodes assiociated to the iproc processor?
20843  // 5) If yes the element is a halo in the iproc processor whose
20844  // nonhalo counter part (haloed) lives in the domain assigned to the
20845  // element
20846  Vector<Vector<Vector<FiniteElement*> > > new_local_halo_element_pt(nproc);
20847 
20848  // Loop over the processors
20849  for (unsigned iproc = 0; iproc < nproc; iproc++)
20850  {
20851  // Resize the container
20852  new_local_halo_element_pt[iproc].resize(nproc);
20853 
20854  // Boolean to know which elements have been already added to the
20855  // new local halo scheme in "iproc"
20856  Vector<std::map<FiniteElement*,bool> > new_local_halo_already_added(nproc);
20857 
20858  // Go through all the elements and identify the new local halo
20859  // elements of "iproc"
20860  unsigned nh_count5 = 0;
20861  for (unsigned e = 0; e < nelement_before_load_balance; e++)
20862  {
20863  // Get the element
20864  FiniteElement *ele_pt = this->finite_element_pt(e);
20865  // Only work with nonhalo elements
20866  if (!(ele_pt->is_halo()))
20867  {
20868  // Get the domain to which the current element is associated
20869  const unsigned ele_domain =
20870  target_domain_for_local_non_halo_element[nh_count5++];
20871  // If the current element is not associated to the "iproc"
20872  // processor then it could be a halo element
20873  if (ele_domain != iproc)
20874  {
20875  // Get the number of nodes
20876  const unsigned nnodes = ele_pt->nnode();
20877  // Loop over the nodes
20878  for (unsigned j = 0; j < nnodes; j++)
20879  {
20880  Node* node_pt = ele_pt->node_pt(j);
20881  // Check if the node is associated with the current
20882  // "iproc" processor
20883  std::set<unsigned>::iterator it =
20884  processors_associated_with_data_before_load_balance[node_pt].
20885  find(iproc);
20886  // If it is found then the element is a halo-element
20887  if (it!=
20888  processors_associated_with_data_before_load_balance[node_pt].
20889  end())
20890  {
20891  // Add the element as new local-halo element with the
20892  // "ele_domain" processor. The non-halo counterpart will
20893  // be located on "ele_domain" processor after sending
20894  // elements across
20895  if (!new_local_halo_already_added[ele_domain][ele_pt])
20896  {
20897  // The element is a halo element on "iproc" with
20898  // "ele_domain"
20899  new_local_halo_element_pt[iproc][ele_domain].
20900  push_back(ele_pt);
20901  // Mark as done
20902  new_local_halo_already_added[ele_domain][ele_pt] = true;
20903  } // if (!new_local_halo_already_added[ele_domain][ele_pt])
20904  } // One of the nodes lies on an element on the current
20905  // "iproc" processor
20906  } // for (j < nnodes)
20907  } // if (ele_domain != iproc)
20908  } // if (!(ele_pt->is_halo()))
20909  } // for (e < nelement_before_load_balance)
20910 
20911  // Now do the same with the halo elements, we need to find those
20912  // halo elements that continue being halo elements but possibly
20913  // with/on another processor. The pair of processors where a
20914  // possible shared boundary is created needs to be notified.
20915 
20916  // Example
20917  //
20918  // ---------------* *---------------
20919  // | |* *| |
20920  // | |* *| |
20921  // | New domain |* *| New domain | * Mark the position
20922  // | proc 1 |* *| proc 3 | of halo elements
20923  // | |* *| |
20924  // | |* *| |
20925  // ---------------* *---------------
20926  // Proc 1 Proc 2
20927 
20928  // Processor 1: The halo elements on processor 1 continue being halo ON
20929  // PROCESSOR 1, but now WITH PROCESSOR 3
20930 
20931  // Processor 2: The halo elements on processor 2 continue being
20932  // halo BUT now ON PROCESSOR 3 WITH PROCESSOR 1
20933 
20934  // The current processor (my_rank) also needs to consider the halo
20935  // elements that will be halo elements of other processor with
20936  // another processor. The case of processor 2
20937 
20938  // Loop over all the halo elements in the current processor and
20939  // check if they will be halo with the "iproc" processor
20940  for (unsigned jproc = 0; jproc < nproc; jproc++)
20941  {
20942  // There are no halo elements with myself (the old halo elements
20943  // were halo in the "my_rank" processor)
20944  if (jproc != my_rank)
20945  {
20946  // Get the number of halo elements with the "jproc" processor
20947  const unsigned n_halo_ele_jproc = this->nroot_halo_element(jproc);
20948  // Get the halo elements with the "jproc" processor
20949  Vector<GeneralisedElement*> halo_element_pt_jproc =
20950  this->root_halo_element_pt(jproc);
20951  // ... and check if any of those elements is a new halo
20952  // element with the "iproc" processor
20953  for (unsigned jh = 0; jh < n_halo_ele_jproc; jh++)
20954  {
20955  // Get the new domain for the halo element
20956  const unsigned ele_domain = new_domains_halo_elements[jproc][jh];
20957 
20958  // If the current element is not associated to the "iproc"
20959  // processor then it could be a halo element on "iproc" with
20960  // "ele_domain".
20961 
20962  // NOTE OUTDATE: Check if the halo element is going to be
20963  // sent to this processor (my_rank), if that is the case
20964  // then we don't need to add it to the set of new halo
20965  // elements with any other processor since any possible
20966  // shared boundary will be created when checking for the
20967  // intersection of the sent and received elements
20968 
20969  //if (ele_domain != iproc && ele_domain != my_rank)
20970 
20971  // NOTE UPDATE: Only check if the halo element is not going
20972  // to be part of the iproc processor, not required to avoid
20973  // those halo elements whose domain is the current rank
20974  // (my_rank). When the shared boundaries are computed, these
20975  // last elements can not create a shared boundary since no
20976  // haloed elements (that shared an edge) are found for
20977  // them. By considering also those halo elements whose new
20978  // domain is the current one (commenting "ele_domain !=
20979  // my_rank") the current processor can compute shared
20980  // boundaries with the iproc processor with help of its old
20981  // halo elements but that will become nonhalo elements, in
20982  // fact they will become haloed elements The halo element is
20983  // not sent to the "element_domain" processor and is not
20984  // passed to the array used to create the new shared
20985  // boundaries "new_shared_boundary_element_pt" because of
20986  // its halo condition
20987  if (ele_domain != iproc)
20988  {
20989  // Get the finite element
20990  FiniteElement* ele_pt =
20991  dynamic_cast<FiniteElement*>(halo_element_pt_jproc[jh]);
20992  // Get the number of nodes on the halo element
20993  const unsigned nnodes = ele_pt->nnode();
20994  // Loop over the nodes
20995  for (unsigned j = 0; j < nnodes; j++)
20996  {
20997  // Get each node of the halo element
20998  Node* node_pt = ele_pt->node_pt(j);
20999 
21000  // Check if the node is associated with the "iproc"
21001  // processor
21002  std::set<unsigned>::iterator it =
21003  processors_associated_with_data_before_load_balance[node_pt].
21004  find(iproc);
21005  // If it is found then the element is a halo-element
21006  if (it!=
21007  processors_associated_with_data_before_load_balance[node_pt].end())
21008  {
21009  // Add the element as new local-halo element with
21010  // the "ele_domain" processor. The non-halo
21011  // counterpart will be located on "ele_domain"
21012  // processor. Because this is a old-halo element it
21013  // will not be sent to the "element_domain" processor
21014  if (!new_local_halo_already_added[ele_domain][ele_pt])
21015  {
21016  // The element is a halo element on "iproc" with
21017  // "ele_domain"
21018  new_local_halo_element_pt[iproc][ele_domain].
21019  push_back(ele_pt);
21020  new_local_halo_already_added[ele_domain][ele_pt] = true;
21021 
21022  // Break the for of the nodes, the element has been
21023  // already added to the new_local_halo_element_pt
21024  // structure
21025  break;
21026 
21027  } // if (!new_local_halo_already_added[ele_domain][ele_pt])
21028 
21029  } // One of the nodes lies on an element belonging to
21030  // "iproc" processor
21031 
21032  } // for (j < nnodes)
21033 
21034  } // if (ele_domain != iproc)
21035 
21036  } // for (jh < n_halo_ele_jproc)
21037 
21038  } // if (jproc != my_rank) // The old halo elements are halo
21039  // with other processors except with "my_rank"
21040 
21041  } // for (jproc < nproc): This is the one that goes for the halo
21042  // elements in the current processor to find the new halo
21043  // elements
21044 
21045  } // for (iproc < nproc)
21046 
21047  // Get the time to compute new local halo elements within all
21048  // processors
21049  if (Print_timings_level_load_balance>1)
21050  {
21051  oomph_info << "CPU for computing new local halo elements (load balance) [4]: "
21052  <<TimingHelpers::timer()-tt_start_compute_new_local_halo_elements
21053  << std::endl;
21054  }
21055 
21056  // =====================================================================
21057  // END: COMPUTE THE NEW LOCAL HALO ELEMENTS OF ALL PROCESSORS IN THE
21058  // CURRENT PROCESSOR
21059  // ----- FOR NONHALO ELEMENTS AND FOR HALO ELEMENTS
21060  // =====================================================================
21061 
21062  // =====================================================================
21063  // BEGIN: COMPUTE THE NEW LOCAL SHARED BOUNDARY ELEMENTS AND THE
21064  // FACE ELEMENTS. THE SUBSET OF THE ELEMENTS TO SENT THAT ARE PART
21065  // OF THE NEW LOCAL SHARED BOUNDARY ELEMENTS ARE IDENTIFIED TO BE
21066  // MARKED AS HALOED ELEMENTS AND BELONGING TO THE SHARED BOUNDARY
21067  // ELEMENTS IN THE RECEIVED PROCESSOR
21068  // =====================================================================
21069 
21070  // Get the time to compute new local shared boundary elements
21071  double tt_start_compute_new_local_shd_bnd_ele=0.0;
21072  if (Print_timings_level_load_balance>1)
21073  {
21074  tt_start_compute_new_local_shd_bnd_ele=TimingHelpers::timer();
21075  }
21076 
21077  // Store the new local-shared boundary elements and the face indexes
21078  // The halo elements and halo face indexes
21079  Vector<Vector<Vector<FiniteElement*> > >
21080  new_local_halo_shared_boundary_element_pt(nproc);
21081  Vector<Vector<Vector<unsigned> > >
21082  new_local_halo_shared_boundary_element_face_index(nproc);
21083 
21084  // Allocate enough memory for the containers
21085  for (unsigned iproc = 0; iproc < nproc; iproc++)
21086  {
21087  new_local_halo_shared_boundary_element_pt[iproc].resize(nproc);
21088  new_local_halo_shared_boundary_element_face_index[iproc].resize(nproc);
21089  } // for (iproc < nproc)
21090 
21091  // Get the elements that create the new local-halo-shared
21092  // boundaries, mark them and identify the face that lies on the
21093  // shared boundary. The new local-halo-shared boundary elements are
21094  // actually a sub-set of the halo elements of each processor with in
21095  // each processor
21096  for (unsigned iproc = 0; iproc < nproc; iproc++)
21097  {
21098  // Star from jproc = iproc + 1 to avoid double creation of shared
21099  // boundary elements, any shared boundary element identified
21100  // between processor "iproc" and "jproc" is also established as
21101  // shared boundary element between processor "jproc" and "iproc"
21102  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
21103  {
21104  this->get_shared_boundary_elements_and_face_indexes(
21105  new_local_halo_element_pt[iproc][jproc],
21106  new_local_halo_element_pt[jproc][iproc],
21107  new_local_halo_shared_boundary_element_pt[iproc][jproc],
21108  new_local_halo_shared_boundary_element_face_index[iproc][jproc],
21109  new_local_halo_shared_boundary_element_pt[jproc][iproc],
21110  new_local_halo_shared_boundary_element_face_index[jproc][iproc]);
21111  } // for (jproc < nproc)
21112  } // for (iproc < nproc)
21113 
21114  // The time to compute new local shared boundary elements
21115  if (Print_timings_level_load_balance>1)
21116  {
21117  oomph_info << "CPU for computing new local shared boundary elements (load balance) [5]: "
21118  <<TimingHelpers::timer()-tt_start_compute_new_local_shd_bnd_ele
21119  << std::endl;
21120  }
21121 
21122  // =====================================================================
21123  // END: COMPUTE THE NEW LOCAL SHARED BOUNDARY ELEMENTS AND THE FACE
21124  // ELEMENTS. THE SUBSET OF THE ELEMENTS TO SENT THAT ARE PART OF THE
21125  // NEW LOCAL SHARED BOUNDARY ELEMENTS ARE IDENTIFIED TO BE MARKED AS
21126  // HALOED ELEMENTS AND BELONGING TO THE SHARED BOUNDARY ELEMENTS IN
21127  // THE RECEIVED PROCESSOR
21128  // =====================================================================
21129 
21130  // =====================================================================
21131  // BEGIN: SEND THE ELEMENTS AND IDENTIFY THOSE THAT ARE PART OF THE
21132  // SHARED BOUNDARIES AND HALOED WITH OTHER PROCESSORS
21133  // =====================================================================
21134 
21135  // Get the time to send the elements to their new processor in
21136  // charge
21137  double tt_start_send_elements_to_other_processors=0.0;
21138  if (Print_timings_level_load_balance>1)
21139  {
21140  tt_start_send_elements_to_other_processors=TimingHelpers::timer();
21141  }
21142 
21143  // Sort the nodes on shared boundaries so that they have the same
21144  // order on all the shared boundaries, this is required to know the
21145  // possible shared nodes among processors
21146  this->sort_nodes_on_shared_boundaries();
21147 
21148  // Store the received elements from each processor
21149  Vector<Vector<FiniteElement*> > received_elements_pt(nproc);
21150 
21151  // The haloed elements and haloed face indexes, these store the
21152  // haloed elements received from "iproc" but that are haloed with
21153  // "jproc". The elements are received from "iproc" which was the
21154  // processor that computed the haloed relation of the "my_rank"
21155  // processor with "jproc"
21156  Vector<Vector<Vector<FiniteElement*> > >
21157  new_received_haloed_shared_boundary_element_pt(nproc);
21158  Vector<Vector<Vector<unsigned> > >
21159  new_received_haloed_shared_boundary_element_face_index(nproc);
21160 
21161  // Container where to store the nodes on shared boundaries not
21162  // associated with the processor that receives the elements/nodes
21163  // other_proc_shd_bnd_node_pt[iproc][jproc][shd_bnd_id][index]
21164  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
21165  other_proc_shd_bnd_node_pt(nproc);
21166  // Resize the container
21167  for (unsigned iproc = 0; iproc < nproc; iproc++)
21168  {
21169  // Resize the container
21170  other_proc_shd_bnd_node_pt[iproc].resize(nproc);
21171  for (unsigned jproc = 0; jproc < nproc; jproc++)
21172  {
21173  // Get the number of shared boundaries (OLD shared boundaries)
21174  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
21175  const unsigned final_shd_bnd_id = this->final_shared_boundary_id();
21176  const unsigned n_shared_bound = final_shd_bnd_id - initial_shd_bnd_id;
21177  other_proc_shd_bnd_node_pt[iproc][jproc].resize(n_shared_bound);
21178  } // for (jproc < nproc)
21179 
21180  } // for (iproc < nproc)
21181 
21182  // Store the global node names
21183  // global_node_name[x][ ][ ] Global node number
21184  // global_node_name[ ][x][ ] Global node names
21185  // global_node_name[ ][ ][x] Global node info.
21186  Vector<Vector<Vector<unsigned> > > global_node_names;
21187 
21188  // Creates a map between the node name and the index of the global
21189  // node so we can access all its node names
21190  std::map<Vector<unsigned>, unsigned> node_name_to_global_index;
21191 
21192  // Store the global shared nodes pointers
21193  Vector<Node*> global_shared_node_pt;
21194 
21195  // Compute all the names of the nodes and fill in the
21196  // "other_proc_shd_bnd_node_pt" structure with the nodes that live
21197  // on this processor (my_rank) by looking over all their names
21198  compute_global_node_names_and_shared_nodes(other_proc_shd_bnd_node_pt,
21199  global_node_names,
21200  node_name_to_global_index,
21201  global_shared_node_pt);
21202 
21203  // From the elements received from each processor, store the haloed
21204  // information of the element, it means, the processor with which it
21205  // is haloed and the haloed index with that processor
21206  Vector<Vector<std::map<unsigned,FiniteElement*> > >
21207  received_old_haloed_element_pt(nproc);
21208  // [x][][] : The receiver processor (the original processor)
21209  // [][x][] : The processor with which the receiver processor has
21210  // haloed elements
21211  // [][][x]: The haloed element number
21212 
21213  // Resize the container
21214  for (unsigned iproc = 0; iproc < nproc; iproc++)
21215  {
21216  received_old_haloed_element_pt[iproc].resize(nproc);
21217  } // for (iproc < nproc)
21218 
21219  // Go through all processors and send the corresponding elements to
21220  // each one
21221  for (unsigned iproc = 0; iproc < nproc; iproc++)
21222  {
21223  if (iproc != my_rank)
21224  {
21225  // -----------------------------------------------------------
21226  // Send (package) information of the elements
21227  // -----------------------------------------------------------
21228 
21229  // Keep track of the currently sent elements
21230  Vector<FiniteElement*> currently_sent_elements;
21231  // Keep track of the currently sent nodes to the iproc processor
21232  Vector<Node*> currently_sent_nodes;
21233 
21234  // Clear send and receive buffers
21235  Flat_packed_unsigneds.clear();
21236  Flat_packed_doubles.clear();
21237 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21238  Flat_packed_unsigneds_string.clear();
21239 #endif
21240 
21241  // Get the number of elements to send to iproc processor
21242  const unsigned nelements_to_send = elements_to_send_pt[iproc].size();
21243 
21244  // The very first data of the flat package sent to processor
21245  // iproc is the number of elements that will be sent, this data
21246  // is used by the receiver processor to loop over the number of
21247  // expected elements to receive
21248  Flat_packed_unsigneds.push_back(nelements_to_send);
21249 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21250  std::stringstream junk;
21251  junk << "Number of elements to send from processor " << my_rank
21252  << " to processor " << iproc << ": ("
21253  << nelements_to_send << ")";
21254  Flat_packed_unsigneds_string.push_back(junk.str());
21255 #endif
21256 
21257  // Loop over the elements to sent
21258  for (unsigned e = 0; e < nelements_to_send; e++)
21259  {
21260  // Get the element to send
21261  FiniteElement* send_ele_pt = elements_to_send_pt[iproc][e];
21262 
21263  // Get the current number of sent elements
21264  const unsigned ncurrently_sent_elements =
21265  currently_sent_elements.size();
21266 
21267  // Try to add the element
21268  const unsigned index_ele = try_to_add_element_pt_load_balance(
21269  currently_sent_elements, send_ele_pt);
21270 
21271  // Element needs to be added
21272  if (index_ele == ncurrently_sent_elements)
21273  {
21274  Flat_packed_unsigneds.push_back(1);
21275 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21276  Flat_packed_unsigneds_string.push_back("Element needs to be constructed");
21277 #endif
21278 
21279  // Get required info. related with the element
21280  get_required_elemental_information_load_balance_helper(
21281  iproc,
21282  f_haloed_element_pt,
21283  send_ele_pt);
21284 
21285  // Get the number of nodes in the element
21286  const unsigned nnodes = send_ele_pt->nnode();
21287 
21288  // Loop over the nodes in the element
21289  for (unsigned j = 0; j < nnodes; j++)
21290  {
21291  Node* node_pt = send_ele_pt->node_pt(j);
21292 
21293  // Package the info. of the nodes
21294  add_node_load_balance_helper(iproc, // The destination process
21295  f_halo_element_pt,
21296  currently_sent_nodes,
21297  node_pt);
21298 
21299  } // for (j < nnodes)
21300 
21301  } // if (index_ele == ncurrently_sent_elements)
21302  else
21303  {
21304  Flat_packed_unsigneds.push_back(0);
21305 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21306  Flat_packed_unsigneds_string.push_back("Element already exists");
21307 #endif
21308  Flat_packed_unsigneds.push_back(index_ele);
21309 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21310  Flat_packed_unsigneds_string.push_back("Index of existing element");
21311 #endif
21312  } // else if (index_ele == ncurrently_sent_elements)
21313 
21314  } // for (e < nelements_to_send)
21315 
21316  // After storing the info. of the elements identify the indexes
21317  // of the "new_local_halo_shared_boundary_elements" in the
21318  // "currently_send_elements" vector, these elements will be
21319  // identified as "new_received_haloed_shared_boundary_elements"
21320  // on the "receiver" processor
21321 
21322  // Each processor has information of every other processor so we
21323  // need to send all the corresponding info. to the other
21324  // processors. Processor 1 may have information of the relation
21325  // (halo elements) between processor 3 and 4 say, so processor 1
21326  // needs to let know processor 3 and 4 what this relation is
21327  // (which are the shared-elements among these processors)
21328 
21329  for (unsigned jproc = 0; jproc < nproc; jproc++)
21330  {
21331  // Get the number of new local-halo shared boundary elements
21332  // between processor "jproc" and "iproc" (we invert the index
21333  // since we really want the haloed elements, those elements
21334  // that we have just sent)
21335  const unsigned njproc_iproc_new_local_halo_shared_boundary_ele =
21336  new_local_halo_shared_boundary_element_pt[jproc][iproc].size();
21337 
21338  // The vector with the info. of the indexes
21339  Vector<unsigned> new_local_halo_shared_boundary_ele_index;
21340 
21341  // The number of found shared boundary elements in the sent
21342  // container (only consider the nonhalo elements)
21343  unsigned nfound_new_local_halo_shared_bound_ele_index = 0;
21344  // The number of nonhalo elements in the new local halo shared
21345  // boundary elements
21346  unsigned nnon_halo_new_local_halo_shared_bound_ele = 0;
21347 
21348  // Loop over the local halo shared boundary elements between
21349  // processor jproc and iproc
21350  for (unsigned e = 0;
21351  e < njproc_iproc_new_local_halo_shared_boundary_ele; e++)
21352  {
21353  // Get the shared boundary element
21354  FiniteElement* shared_ele_pt =
21355  new_local_halo_shared_boundary_element_pt[jproc][iproc][e];
21356 
21357  // Only consider the nonhalo elements since the halo
21358  // elements were no considered for sending
21359  if (!shared_ele_pt->is_halo())
21360  {
21361  nnon_halo_new_local_halo_shared_bound_ele++;
21362 
21363  // Now find the index on the currently sent elements
21364 
21365  // Get the current number of sent elements
21366  const unsigned ncurrently_sent_elements =
21367  currently_sent_elements.size();
21368  // Loop over the sent elements
21369  for (unsigned ics = 0; ics < ncurrently_sent_elements; ics++)
21370  {
21371  FiniteElement* currently_sent_ele_pt =
21372  currently_sent_elements[ics];
21373 
21374  // Is this the element?
21375  if (currently_sent_ele_pt == shared_ele_pt)
21376  {
21377  // Store the index on the sent elements of the local
21378  // halo shared boundary element
21379  new_local_halo_shared_boundary_ele_index.push_back(ics);
21380  // Increase the number of found new local halo shared
21381  // bound element index
21382  nfound_new_local_halo_shared_bound_ele_index++;
21383  // We have found it, no need to further search
21384  break;
21385  } // if (currently_sent_ele_pt == shared_ele_pt)
21386 
21387  } // for (ics < ncurrently_sent_elements)
21388 
21389  } // if (!shared_ele_pt->is_halo())
21390 
21391  } // for (e < niproc_new_local_halo_shared_boundary_ele)
21392 
21393 #ifdef PARANOID
21394  if (nfound_new_local_halo_shared_bound_ele_index !=
21395  nnon_halo_new_local_halo_shared_bound_ele)
21396  {
21397  std::ostringstream error_message;
21398  error_message
21399  << "Was only possible to identify ("
21400  << nfound_new_local_halo_shared_bound_ele_index << ") of ("
21401  << nnon_halo_new_local_halo_shared_bound_ele << ") shared "
21402  << "elements between\nprocessor ("<<iproc<<") and ("<<jproc<<") "
21403  << "when sending elements to processor ("<<iproc<<")\n\n";
21404  throw OomphLibError(error_message.str(),
21405  OOMPH_CURRENT_FUNCTION,
21406  OOMPH_EXCEPTION_LOCATION);
21407  }
21408 #endif
21409 
21410  // Send a flag for synchronisation issues
21411  Flat_packed_unsigneds.push_back(9999);
21412 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21413  std::stringstream junk;
21414  junk << "Flag for synchronisation 9999";
21415  Flat_packed_unsigneds_string.push_back(junk.str());
21416 #endif
21417 
21418  // Send the number of nonhalo new local-shared boundary
21419  // elements of processor "iproc" with processor "jproc"
21420  Flat_packed_unsigneds.push_back(nnon_halo_new_local_halo_shared_bound_ele);
21421 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21422  std::stringstream junk2;
21423  junk2 << "Number of new local halo shared boundary elements "
21424  << nnon_halo_new_local_halo_shared_bound_ele;
21425  Flat_packed_unsigneds_string.push_back(junk2.str());
21426 #endif
21427 
21428  // Send the indexes and the face indexes of the shared
21429  // boundary elements
21430  unsigned counter_nonhalo_sent = 0;
21431  // Loop over the local halo shared boundary elements between
21432  // processor jproc and iproc
21433  for (unsigned e = 0;
21434  e < njproc_iproc_new_local_halo_shared_boundary_ele; e++)
21435  {
21436  // Get the shared boundary element
21437  FiniteElement* shared_ele_pt =
21438  new_local_halo_shared_boundary_element_pt[jproc][iproc][e];
21439 
21440  // Only consider the nonhalo elements since the halo
21441  // elements were no considered for sending
21442  if (!shared_ele_pt->is_halo())
21443  {
21444  // Get the index on the sent elements of the current
21445  // nonhalo shared boundary element
21446  const unsigned ele_index =
21447  new_local_halo_shared_boundary_ele_index[counter_nonhalo_sent++];
21448  // ... and get the face index
21449  const unsigned face_index =
21450  new_local_halo_shared_boundary_element_face_index[jproc][iproc][e];
21451 
21452  // Send the index on the sent elements of the new local
21453  // halo shared boundary element
21454  Flat_packed_unsigneds.push_back(ele_index);
21455 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21456  std::stringstream junk;
21457  junk << "The index of the halo shared boundary element "
21458  << ele_index;
21459  Flat_packed_unsigneds_string.push_back(junk.str());
21460 #endif
21461 
21462  // Send the face index of the new local halo shared boundary
21463  // element
21464  Flat_packed_unsigneds.push_back(face_index);
21465 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21466  std::stringstream junk2;
21467  junk2 << "The face index of the halo shared boundary element "
21468  << face_index;
21469  Flat_packed_unsigneds_string.push_back(junk2.str());
21470 #endif
21471 
21472  } // if (!shared_ele_pt->is_halo())
21473 
21474  } // for (e < niproc_new_local_halo_shared_boundary_ele)
21475 
21476  } // for (jproc < nproc)
21477 
21478  // ----------------------------------------------------------
21479  // Send the info. perform the communications
21480  // ----------------------------------------------------------
21481  // Processor to which send the info.
21482  int send_proc = static_cast<int>(iproc);
21483  // Processor from which receive the info.
21484  int recv_proc = static_cast<int>(iproc);
21485  send_and_receive_elements_nodes_info(send_proc, recv_proc);
21486 
21487  // ----------------------------------------------------------
21488  // Receive (unpackage) the info of the elements
21489  // ----------------------------------------------------------
21490 
21491  // Keep track of the currently created elements
21492  Vector<FiniteElement*> currently_created_elements;
21493  // Keep track of the currently created nodes
21494  Vector<Node*> currently_created_nodes;
21495 
21496  // Reset the counters
21497  Counter_for_flat_packed_doubles=0;
21498  Counter_for_flat_packed_unsigneds=0;
21499 
21500 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
21501  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
21502  << " Number of elements need to be constructed "
21503  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
21504  << std::endl;
21505 #endif
21506 
21507  // Read the number of elements that need to be created
21508  const unsigned nelements_to_create =
21509  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
21510 
21511  for (unsigned e = 0; e < nelements_to_create; e++)
21512  {
21513  // Create the element from received info. of "iproc"
21514  // processor on the current processor
21515  create_element_load_balance_helper(iproc,
21516  f_haloed_element_pt,
21517  received_old_haloed_element_pt,
21518  currently_created_elements,
21519  currently_created_nodes,
21520  other_proc_shd_bnd_node_pt,
21521  global_node_names,
21522  node_name_to_global_index,
21523  global_shared_node_pt);
21524  }
21525 
21526  // Copy the received elements from "iproc" processor
21527 
21528  // Number of received elements
21529  const unsigned nreceived_elements = currently_created_elements.size();
21530  received_elements_pt[iproc].resize(nreceived_elements);
21531  for (unsigned e = 0; e < nreceived_elements; e++)
21532  {received_elements_pt[iproc][e] = currently_created_elements[e];}
21533 
21534  // Go for the haloed elements received from processor "iproc"
21535  // but haloed with "jproc"
21536 
21537  // Allocate memory for the containers
21538  new_received_haloed_shared_boundary_element_pt[iproc].resize(nproc);
21539  new_received_haloed_shared_boundary_element_face_index[iproc].resize(nproc);
21540 
21541  // Loop over the processors
21542  for (unsigned jproc = 0; jproc < nproc; jproc++)
21543  {
21544  // Read the synchronisation flag
21545  const unsigned synchronisation_flag =
21546  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
21547 
21548  if (synchronisation_flag != 9999)
21549  {
21550  std::ostringstream error_message;
21551  error_message
21552  << "The synchronisation flag was not read, the\n"
21553  << "information sent between processor (" << my_rank << ") "
21554  << "and ("<< iproc << ")\nis no longer synchronised\n\n";
21555  throw OomphLibError(error_message.str(),
21556  OOMPH_CURRENT_FUNCTION,
21557  OOMPH_EXCEPTION_LOCATION);
21558  }
21559 
21560  // Read the number of elements that will be part of the new
21561  // received haloed shared boundary elements received from "iproc"
21562  // and haloed with "jproc"
21563  const unsigned niproc_jproc_new_received_haloed_shared_boundary_ele =
21564  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
21565 
21566  // Loop over the new received haloed shared boundary elements
21567  for (unsigned e = 0;
21568  e < niproc_jproc_new_received_haloed_shared_boundary_ele; e++)
21569  {
21570  // Read the index of the new received haloed shared boundary
21571  // ele with "jproc"
21572  const unsigned ele_index =
21573  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
21574  // Read the face index for the new received haloed shared
21575  // boundary element
21576  const unsigned face_index =
21577  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
21578 
21579  // Get the element
21580  FiniteElement* shared_ele_pt =
21581  currently_created_elements[ele_index];
21582 
21583  // Add the element to the new received-haloed shared
21584  // boundary elements. Received from "iproc" but haloed with
21585  // "jproc" processor
21586  new_received_haloed_shared_boundary_element_pt[iproc][jproc].
21587  push_back(shared_ele_pt);
21588  // Store the face index
21589  new_received_haloed_shared_boundary_element_face_index[iproc][jproc].
21590  push_back(face_index);
21591 
21592  } // for (e < niproc_jproc_read_new_local_shared_boundary_ele)
21593 
21594  } // for (jproc < nproc)
21595 
21596  } // if (iproc != my_rank)
21597 
21598  } // for (iproc < nproc)
21599 
21600  // The time to send the elements to their new processor in charge
21601  if (Print_timings_level_load_balance>1)
21602  {
21603  oomph_info << "CPU for sending elements to their new processors (load balance) [6]: "
21604  <<TimingHelpers::timer()-tt_start_send_elements_to_other_processors
21605  << std::endl;
21606  }
21607 
21608  // =====================================================================
21609  // END: SEND THE ELEMENTS AND IDENTIFY THOSE THAT ARE PART OF THE
21610  // SHARED BOUNDARIES AND HALOED WITH OTHER PROCESSORS
21611  // =====================================================================
21612 
21613  // =====================================================================
21614  // BEGIN: GET ANY ADDITIONAL SHARED BOUNDARY BY THE INTERSECTION OF
21615  // THE ELEMENTS SENT TO PROCESSOR "IPROC" AND THE ELEMENTS RECEIVED
21616  // FROM PROCESSOR "IPROC". IF ANY NEW SHARED BOUNDARY IS FOUND, IT
21617  // IS CREATED BY THE OLD HALO ELEMENTS (RECEIVED ELEMENTS) THAT HAVE
21618  // NOW BECOME PART OF THE DOMAIN AND THE OLD HALOED ELEMENTS (SENT
21619  // ELEMENTS)
21620  // =====================================================================
21621 
21622  // Get the time to compute any additional shared boundary
21623  double tt_start_compute_additional_shared_boundaries=0.0;
21624  if (Print_timings_level_load_balance>1)
21625  {
21626  tt_start_compute_additional_shared_boundaries=TimingHelpers::timer();
21627  }
21628 
21629  // Store any additional elements that may create a shared boundary,
21630  // after sending elements from one to other processor check for any
21631  // new possible shared boundaries
21632  Vector<Vector<FiniteElement*> >
21633  tmp_group1_shared_boundary_element_pt(nproc);
21634  Vector<Vector<unsigned> >
21635  tmp_group1_shared_boundary_element_face_index(nproc);
21636  Vector<Vector<FiniteElement*> >
21637  tmp_group2_shared_boundary_element_pt(nproc);
21638  Vector<Vector<unsigned> >
21639  tmp_group2_shared_boundary_element_face_index(nproc);
21640 
21641  // Compute any additional shared boundaries by checking the
21642  // intersection between the received elements from each processor
21643  // and the elements just sent to that processor, the lowest
21644  // processors number loops over its received elements and the
21645  // highest loops over its sent elements (halo elements that have
21646  // become part of the domain now can create shared boundaries with
21647  // other processor)
21648 
21649  // Note: These additional shared boundaries may be created by the
21650  // elements that previously were halo but now have become part of
21651  // the processor (the received elements), and the elements that were
21652  // previously part of the processor but now have become halo (a
21653  // subset of the sent-elements)
21654 
21655  // Then these new shared boundaries come from the intersection of
21656  // the new-haloed elements (received elements) and the new-halo
21657  // elements (sent elements). These could be computed previously (in
21658  // the computing of the local new-halo and local new-haloed elements
21659  // usign the info. of the new domains for the old halo elements),
21660  // however, it was decided to perform the computation here in order to
21661  // avoid the identification of the old halo element that was part of a
21662  // shared boundary in the set of just received elements
21663  for (unsigned iproc = 0; iproc < nproc; iproc++)
21664  {
21665  if (my_rank < iproc)
21666  {
21667  // Lowest processor loops over the received elements
21668  this->get_shared_boundary_elements_and_face_indexes(
21669  received_elements_pt[iproc], elements_to_send_pt[iproc],
21670  tmp_group1_shared_boundary_element_pt[iproc],
21671  tmp_group1_shared_boundary_element_face_index[iproc],
21672  tmp_group2_shared_boundary_element_pt[iproc],
21673  tmp_group2_shared_boundary_element_face_index[iproc]);
21674 
21675  } // if (my_rank < iproc)
21676  else if (my_rank > iproc)
21677  {
21678  // Highest processor loops over the sent elements
21679  this->get_shared_boundary_elements_and_face_indexes(
21680  elements_to_send_pt[iproc], received_elements_pt[iproc],
21681  tmp_group1_shared_boundary_element_pt[iproc],
21682  tmp_group1_shared_boundary_element_face_index[iproc],
21683  tmp_group2_shared_boundary_element_pt[iproc],
21684  tmp_group2_shared_boundary_element_face_index[iproc]);
21685 
21686  } // else if (my_rank > iproc)
21687 
21688  } // for (iproc < nproc)
21689 
21690  // The time to compute any additional shared boundary
21691  if (Print_timings_level_load_balance>1)
21692  {
21693  oomph_info << "CPU for computing additional shared boundaries (load balance) [7]: "
21694  <<TimingHelpers::timer()-tt_start_compute_additional_shared_boundaries
21695  << std::endl;
21696  }
21697 
21698  // =====================================================================
21699  // END: GET ANY ADDITIONAL SHARED BOUNDARY BY THE INTERSECTION OF
21700  // THE ELEMENTS SENT TO PROCESSOR "IPROC" AND THE ELEMENTS RECEIVED
21701  // FROM PROCESSOR "IPROC". IF ANY NEW SHARED BOUNDARY IS FOUND, IT
21702  // IS CREATED BY THE OLD HALO ELEMENTS (RECEIVED ELEMENTS) THAT HAVE
21703  // NOW BECOME PART OF THE DOMAIN AND THE OLD HALOED ELEMENTS (SENT
21704  // ELEMENTS)
21705  // =====================================================================
21706 
21707  // =====================================================================
21708  // BEGIN: SORT THE SHARED BOUNDARIES SO THAT THEY ARE CREATED IN THE
21709  // SAME ORDER IN THE INVOLVED PROCESSORS (A PAIR OF PROCESSORS)
21710  // =====================================================================
21711 
21712  // Get the time to sort shared boundaries
21713  double tt_start_sort_shared_boundaries=0.0;
21714  if (Print_timings_level_load_balance>1)
21715  {
21716  tt_start_sort_shared_boundaries=TimingHelpers::timer();
21717  }
21718 
21719  // Once computed the elements that create the shared boundaries,
21720  // sort them so that the shared boundaries are created at the same
21721  // order in both processors that define the shared boundary
21722 
21723  // The order is like this
21724 
21725  // Lowest processors
21726  // 1) Shared boundary elements received from processors (local in
21727  // other processors)
21728  // 2) Local shared boundary elements (do not include halo elements)
21729  // 3) Shared boundary elements by intersection (already sorted)
21730 
21731  // Highest processors
21732  // 1) Local shared boundary elements (do not include halo elements)
21733  // 2) Shared boundary elements received from processors (local in
21734  // other processors)
21735  // 3) Shared boundary elements by intersection (already sorted)
21736 
21737  Vector<Vector<FiniteElement*> > new_shared_boundary_element_pt(nproc);
21738  Vector<Vector<unsigned> > new_shared_boundary_element_face_index(nproc);
21739  for (unsigned iproc = 0; iproc < nproc; iproc++)
21740  {
21741  // Lower processor
21742  if (my_rank < iproc)
21743  {
21744  // Copy the elements received from processor "jproc" but that
21745  // are haloed with "iproc" processor
21746  for (unsigned jproc = 0; jproc < nproc; jproc++)
21747  {
21748  // Can not receive elements from itself
21749  if (jproc != my_rank)
21750  {
21751  // Get the number of elements to copy from received processors
21752  const unsigned nrecvd_haloed_shared_bound_ele_jproc_iproc =
21753  new_received_haloed_shared_boundary_element_pt[jproc][iproc].size();
21754  for (unsigned e = 0;
21755  e < nrecvd_haloed_shared_bound_ele_jproc_iproc; e++)
21756  {
21757  // Get the element
21758  FiniteElement* ele_pt =
21759  new_received_haloed_shared_boundary_element_pt[jproc][iproc][e];
21760  // Get the face index
21761  const unsigned face_index =
21762  new_received_haloed_shared_boundary_element_face_index[jproc][iproc][e];
21763 
21764  // Add the elements to the containers
21765  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
21766  new_shared_boundary_element_face_index[iproc].push_back(face_index);
21767 
21768  } // for (e < nrecvd_haloed_shared_bound_ele_iproc_jproc)
21769 
21770  } // if (jproc != my_rank)
21771 
21772  } // for (jproc < nproc)
21773 
21774  // Then the local shared haloed (invert the indexes to get the
21775  // haloed elements)
21776  const unsigned nlocal_haloed_shared_bound_ele_iproc_my_rank =
21777  new_local_halo_shared_boundary_element_pt[iproc][my_rank].size();
21778  for (unsigned e = 0;
21779  e < nlocal_haloed_shared_bound_ele_iproc_my_rank; e++)
21780  {
21781  // Get the element
21782  FiniteElement* ele_pt =
21783  new_local_halo_shared_boundary_element_pt[iproc][my_rank][e];
21784  // Get the face index
21785  const unsigned face_index =
21786  new_local_halo_shared_boundary_element_face_index[iproc][my_rank][e];
21787 
21788  // Only include the element if it is nonhalo (this may be an
21789  // old halo element that helped to indentify a shared boundary
21790  // with iproc)
21791  if (!ele_pt->is_halo())
21792  {
21793  // Add the elements to the containers
21794  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
21795  new_shared_boundary_element_face_index[iproc].push_back(face_index);
21796  } // if (!ele_pt->is_halo())
21797 
21798  } // for (e < nlocal_haloed_shared_bound_ele_iproc_my_rank)
21799 
21800  // ... and finally any additional shared boundary elements from
21801  // tmp_group1
21802  const unsigned ntmp_group1_shared_bound_ele_iproc =
21803  tmp_group1_shared_boundary_element_pt[iproc].size();
21804  for (unsigned e = 0; e < ntmp_group1_shared_bound_ele_iproc; e++)
21805  {
21806  // Get the element
21807  FiniteElement* ele_pt =
21808  tmp_group1_shared_boundary_element_pt[iproc][e];
21809  // Get the face index
21810  const unsigned face_index =
21811  tmp_group1_shared_boundary_element_face_index[iproc][e];
21812 
21813  // Add the elements to the containers
21814  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
21815  new_shared_boundary_element_face_index[iproc].push_back(face_index);
21816 
21817  } // for (e < ntmp_group1_shared_bound_ele_iproc)
21818 
21819  } // if (my_rank < iproc)
21820  // Highest processor
21821  else if (my_rank > iproc)
21822  {
21823  // Get the haloed elements first and then the elements received
21824  // from processor "jproc" but that are haloed with "iproc"
21825  // processor
21826 
21827  // Get the number of elements to copy from local elements
21828  // (invert the indexes to get the haloed elements)
21829  const unsigned nlocal_haloed_shared_bound_ele_iproc_my_rank =
21830  new_local_halo_shared_boundary_element_pt[iproc][my_rank].size();
21831  for (unsigned e = 0;
21832  e < nlocal_haloed_shared_bound_ele_iproc_my_rank; e++)
21833  {
21834  // Get the element
21835  FiniteElement* ele_pt =
21836  new_local_halo_shared_boundary_element_pt[iproc][my_rank][e];
21837  // Get the face index
21838  const unsigned face_index =
21839  new_local_halo_shared_boundary_element_face_index[iproc][my_rank][e];
21840 
21841  // Only include the element if it is nonhalo (this may be an
21842  // old halo element that helped to indentify a shared boundary
21843  // with iproc)
21844  if (!ele_pt->is_halo())
21845  {
21846  // Add the elements to the containers
21847  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
21848  new_shared_boundary_element_face_index[iproc].push_back(face_index);
21849  } // if (!ele_pt->is_halo())
21850 
21851  } // for (e < nlocal_haloed_shared_bound_ele_iproc_my_rank)
21852 
21853  for (unsigned jproc = 0; jproc < nproc; jproc++)
21854  {
21855  // Can not receive elements from itself
21856  if (jproc != my_rank)
21857  {
21858  // Then the received shared elements from "jproc" but haloed
21859  // with "iproc"
21860  const unsigned nrecvd_haloed_shared_bound_ele_jproc_iproc =
21861  new_received_haloed_shared_boundary_element_pt[jproc][iproc].size();
21862  for (unsigned e = 0;
21863  e < nrecvd_haloed_shared_bound_ele_jproc_iproc; e++)
21864  {
21865  // Get the element
21866  FiniteElement* ele_pt =
21867  new_received_haloed_shared_boundary_element_pt[jproc][iproc][e];
21868  // Get the face index
21869  const unsigned face_index =
21870  new_received_haloed_shared_boundary_element_face_index[jproc][iproc][e];
21871 
21872  // Add the elements to the containers
21873  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
21874  new_shared_boundary_element_face_index[iproc].push_back(face_index);
21875 
21876  } // for (e < nrecvd_haloed_shared_bound_ele_iproc)
21877 
21878  } // if (jproc != my_rank)
21879 
21880  } // for (jproc < nproc)
21881 
21882  // ... and finally any additional shared boundary elements from
21883  // tmp_group2
21884  const unsigned ntmp_group2_shared_bound_ele_iproc =
21885  tmp_group2_shared_boundary_element_pt[iproc].size();
21886  for (unsigned e = 0; e < ntmp_group2_shared_bound_ele_iproc; e++)
21887  {
21888  // Get the element
21889  FiniteElement* ele_pt =
21890  tmp_group2_shared_boundary_element_pt[iproc][e];
21891  // Get the face index
21892  const unsigned face_index =
21893  tmp_group2_shared_boundary_element_face_index[iproc][e];
21894 
21895  // Add the elements to the containers
21896  new_shared_boundary_element_pt[iproc].push_back(ele_pt);
21897  new_shared_boundary_element_face_index[iproc].push_back(face_index);
21898 
21899  } // for (e < ntmp_group2_shared_bound_ele_iproc)
21900 
21901  } // else if (my_rank > iproc)
21902 
21903  } // for (iproc < nproc)
21904 
21905  // The time to sort shared boundaries
21906  if (Print_timings_level_load_balance>1)
21907  {
21908  oomph_info << "CPU for sorting shared boundaries (load balance) [8]: "
21909  <<TimingHelpers::timer()-tt_start_sort_shared_boundaries
21910  << std::endl;
21911  }
21912 
21913  // =====================================================================
21914  // END: SORT THE SHARED BOUNDARIES SO THAT THEY ARE CREATED IN THE
21915  // SAME ORDER IN THE INVOLVED PROCESSORS (A PAIR OF PROCESSORS)
21916  // =====================================================================
21917 
21918  // =====================================================================
21919  // BEGIN: CREATE THE NEW SHARED BOUNDARIES. BEFORE THE GENERATION OF
21920  // THE SHARED BOUNDARIES PUT IN A CONTAINER THOSE NONHALO ELEMENTS
21921  // THAT WILL REMAIN IN THE CURRENT PROCESSOR (BECAUSE THEIR RANK IS
21922  // THE SAME AS THE CURRENT PROCESSOR), AND THOSE ELEMENTS RECEIVED
21923  // FROM OTHER PROCESSORS. THESE SET OF ELEMENTS WILL BE USED TO
21924  // CHECK FOR POSSIBLE CONNECTIONS OF THE NEW SHARED BOUNDARIES WITH
21925  // THE ORIGINAL BOUNDARIES
21926  // =====================================================================
21927  // Finally, create the new shared boundaries
21928 
21929  // Get the time to create the new shared boundaries
21930  double tt_start_create_new_shared_boundaries=0.0;
21931  if (Print_timings_level_load_balance>1)
21932  {
21933  tt_start_create_new_shared_boundaries=TimingHelpers::timer();
21934  }
21935 
21936  // Compute the elements that will remain after deletion in the
21937  // curent processor. This is required to check if the new shared
21938  // boundaries crete a connection with any node of the elements in
21939  // the boundaries
21940 
21941  // Try to use as much information as possible
21942 
21943  // Storage for the elements in the processor
21944  std::set<FiniteElement*> element_in_processor_pt;
21945 
21946  // Loop over the old elements, those before sending/received
21947  // elements to/from other processors
21948  unsigned nh_count6 = 0;
21949  for (unsigned e = 0; e < nelement_before_load_balance; e++)
21950  {
21951  // Get the element
21952  FiniteElement* ele_pt = backed_up_ele_pt[e];
21953  // Only work with nonhalo elements
21954  if (!(ele_pt->is_halo()))
21955  {
21956  // Is the element part of the new domain
21957  if (target_domain_for_local_non_halo_element[nh_count6++] == my_rank)
21958  {
21959  // Add the element to the set of elements in the processor
21960  element_in_processor_pt.insert(ele_pt);
21961 
21962  }
21963 
21964  } // if (!(ele_pt->is_halo()))
21965 
21966  } // for (e < nelement_before_load_balance)
21967 
21968  // Now include the received elements from the other processors
21969  // Loop over the processors
21970  for (unsigned iproc = 0; iproc < nproc; iproc++)
21971  {
21972  // No elements received from myself
21973  if (iproc != my_rank)
21974  {
21975  // Get the number of received elements with the "iproc"
21976  // processor
21977  const unsigned n_received_ele = received_elements_pt[iproc].size();
21978  for (unsigned ie = 0; ie < n_received_ele; ie++)
21979  {
21980  // Get the ie-th received element from processor iproc
21981  FiniteElement* ele_pt = received_elements_pt[iproc][ie];
21982 
21983  // Include it in the set of elements in the processor
21984  element_in_processor_pt.insert(ele_pt);
21985 
21986  } // for (ie < nreceived_ele)
21987 
21988  } // if (iproc != my_rank)
21989 
21990  } // for (iproc < nproc)
21991 
21992  // Now create the shared boundaries
21993  create_new_shared_boundaries(element_in_processor_pt,
21994  new_shared_boundary_element_pt,
21995  new_shared_boundary_element_face_index);
21996 
21997  // The time to create the new shared boundaries
21998  if (Print_timings_level_load_balance>1)
21999  {
22000  oomph_info << "CPU for creating new shared boundaries (load balance) [9]: "
22001  <<TimingHelpers::timer()-tt_start_create_new_shared_boundaries
22002  << std::endl;
22003  }
22004 
22005  // =====================================================================
22006  // END: CREATE THE NEW SHARED BOUNDARIES. BEFORE THE GENERATION OF
22007  // THE SHARED BOUNDARIES PUT IN A CONTAINER THOSE NONHALO ELEMENTS
22008  // THAT WILL REMAIN IN THE CURRENT PROCESSOR (BECAUSE THEIR RANK IS
22009  // THE SAME AS THE CURRENT PROCESSOR), AND THOSE ELEMENTS RECEIVED
22010  // FROM OTHER PROCESSORS. THESE SET OF ELEMENTS WILL BE USED TO
22011  // CHECK FOR POSSIBLE CONNECTIONS OF THE NEW SHARED BOUNDARIES WITH
22012  // THE ORIGINAL BOUNDARIES
22013  // =====================================================================
22014 
22015  // =====================================================================
22016  // BEGIN: DELETE THE ELEMENTS NO LONGER BELONGING TO THE DOMAIN,
22017  // INCLUDING HALO ELEMENTS. ADD THE KEPT ELEMENTS TO THE MESH AND
22018  // THE RECEIVED ELEMENTS FROM OTHER PROCESSORS
22019  // =====================================================================
22020 
22021  // Get the time to delete elements no longer belonging to the
22022  // processor
22023  double tt_start_delete_elements=0.0;
22024  if (Print_timings_level_load_balance>1)
22025  {
22026  tt_start_delete_elements=TimingHelpers::timer();
22027  }
22028 
22029  // Once computed the new shared boundaries delete the elements that
22030  // no longer belong to the processor (including the old halo
22031  // elements)
22032 
22033  // The procedure is similar to the one performed at the distribution
22034  // stage (src/generic/mesh.cc -- distribute() method)
22035 
22036  // Clean the storage for halo(ed) elements/nodes
22037  this->Halo_node_pt.clear();
22038  this->Root_halo_element_pt.clear();
22039 
22040  this->Haloed_node_pt.clear();
22041  this->Root_haloed_element_pt.clear();
22042 
22043  // Mark all the nodes as obsolete
22044  const unsigned nnodes = this->nnode();
22045  for (unsigned j = 0; j < nnodes; j++)
22046  {
22047  this->node_pt(j)->set_obsolete();
22048  }
22049 
22050  // Flush the mesh storage
22051  this->flush_element_storage();
22052 
22053  // Delete any storage of external elements and nodes
22054  this->delete_all_external_storage();
22055 
22056  // Clear external storage
22057  this->External_halo_node_pt.clear();
22058  this->External_halo_element_pt.clear();
22059 
22060  this->External_haloed_node_pt.clear();
22061  this->External_haloed_element_pt.clear();
22062 
22063  // Keep track of the deleted elements
22064  Vector<FiniteElement*> deleted_elements;
22065 
22066  // Delete the elements that no longer belong to the processor
22067  unsigned nh_count7 = 0;
22068  for (unsigned e = 0; e < nelement_before_load_balance; e++)
22069  {
22070  FiniteElement* ele_pt = backed_up_ele_pt[e];
22071  // Only work with nonhalo elements
22072  if (!(ele_pt->is_halo()))
22073  {
22074  if (target_domain_for_local_non_halo_element[nh_count7++] == my_rank)
22075  {
22076  // Add the element to the mesh
22077  this->add_element_pt(ele_pt);
22078  // Get the number of nodes on the element
22079  const unsigned nele_nodes = ele_pt->nnode();
22080  // Loop over the nodes of the element
22081  for (unsigned j = 0; j < nele_nodes; j++)
22082  {
22083  // Mark the node as non-obsolete
22084  ele_pt->node_pt(j)->set_non_obsolete();
22085  } // for (j < nele_nodes)
22086 
22087  } // The element belongs to the domain
22088  else
22089  {
22090  // Delete the element, but keep track of it
22091  deleted_elements.push_back(ele_pt);
22092  // Delete and point to null
22093  delete ele_pt;
22094  ele_pt = 0;
22095  }
22096 
22097  } // if (!(ele_pt->is_halo()))
22098  else
22099  {
22100  // If the element is halo, delete if but keep track of it
22101  deleted_elements.push_back(ele_pt);
22102  // Delete and point to null
22103  delete ele_pt;
22104  ele_pt = 0;
22105  }
22106 
22107  } // for (e < nelement_before_load_balance)
22108 
22109  // Now add the received elements from each processor
22110  for (unsigned iproc = 0; iproc < nproc; iproc++)
22111  {
22112  if (iproc != my_rank)
22113  {
22114  // Get the number of received elements with the "iproc"
22115  // processor
22116  const unsigned nreceived_ele = received_elements_pt[iproc].size();
22117  for (unsigned ie = 0; ie < nreceived_ele; ie++)
22118  {
22119  // Get the element and add it to the mesh
22120  FiniteElement* ele_pt = received_elements_pt[iproc][ie];
22121  // Add the element to the mesh
22122  this->add_element_pt(ele_pt);
22123  // Get the number of nodes on the element
22124  const unsigned nele_nodes = ele_pt->nnode();
22125  // Loop over the nodes of the element
22126  for (unsigned j = 0; j < nele_nodes; j++)
22127  {
22128  // Mark the node as non-obsolete
22129  ele_pt->node_pt(j)->set_non_obsolete();
22130  } // for (j < nele_nodes)
22131 
22132  } // for (ie < nreceived_ele)
22133 
22134  } // if (iproc != my_rank)
22135 
22136  } // for (iproc < nproc)
22137 
22138  // Now remove the obsolete nodes
22139  this->prune_dead_nodes();
22140 
22141  // The time to delete elements no longer belonging to the processor
22142  if (Print_timings_level_load_balance>1)
22143  {
22144  oomph_info << "CPU for deleting elements no longer belonging to this processor (load balance) [10]: "
22145  <<TimingHelpers::timer()-tt_start_delete_elements
22146  << std::endl;
22147  }
22148 
22149  // =====================================================================
22150  // END: DELETE THE ELEMENTS NO LONGER BELONGING TO THE DOMAIN,
22151  // INCLUDING HALO ELEMENTS. ADD THE KEPT ELEMENTS TO THE MESH AND
22152  // THE RECEIVED ELEMENTS FROM OTHER PROCESSORS
22153  // =====================================================================
22154 
22155  // =====================================================================
22156  // BEGIN: REESTABLISH THE HALO(ED) SCHEME, ATTACH HALO ELEMENTS
22157  // (HALO NODES INCLUDED) TO THE NEW MESH (AFTER LOAD BALANCING)
22158  // RESTORE THE BOUNDARY ELEMENTS SCHEME AND THE NUMBER OF SEGMENTS
22159  // ON EACH BOUNDARY
22160  // =====================================================================
22161 
22162  // Get the time to re-establish the halo(ed) information
22163  double tt_start_re_etablish_halo_ed_info=0.0;
22164  if (Print_timings_level_load_balance>1)
22165  {
22166  tt_start_re_etablish_halo_ed_info=TimingHelpers::timer();
22167  }
22168 
22169  // Prepare the data to re-establish the halo(ed) scheme
22170 
22171  // Sort the nodes on the new shared boundaries so that they have the
22172  // same order on all processors
22173  this->sort_nodes_on_shared_boundaries();
22174 
22175  // Before re-establish the halo and haloed elements save the number
22176  // of current elements in the boundaries, this will be useful to
22177  // re-establish the boundary elements. Notice that there may be
22178  // boundary elements with null pointers, since the element may no
22179  // longer belong to the current processor
22180  const unsigned tmp_nboundary = this->nboundary();
22181  Vector<unsigned> ntmp_boundary_elements(tmp_nboundary);
22182 
22183  // If there are regions, save the number of boundary-region elements
22184  Vector<Vector<unsigned> > ntmp_boundary_elements_in_region(tmp_nboundary);
22185  // Are there regions?
22186  const unsigned n_regions = this->nregion();
22187 
22188  // Loop over the boundaries
22189  for (unsigned ib = 0; ib < tmp_nboundary; ib++)
22190  {
22191  // Get the number of boundary elements
22192  ntmp_boundary_elements[ib] = this->nboundary_element(ib);
22193 
22194  // Resize the container
22195  ntmp_boundary_elements_in_region[ib].resize(n_regions);
22196 
22197  // Loop over the regions
22198  for (unsigned rr = 0 ; rr < n_regions; rr++)
22199  {
22200  // Get the region id
22201  const unsigned region_id =
22202  static_cast<unsigned>(this->region_attribute(rr));
22203 
22204  // Store the number of element in the region (notice we are
22205  // using the region index not the region id to refer to the
22206  // region)
22207  ntmp_boundary_elements_in_region[ib][rr] =
22208  this->nboundary_element_in_region(ib, region_id);
22209 
22210  } // for (rr < n_regions)
22211 
22212  } // for (ib < tmp_nboundary)
22213 
22214  // Re-establish the halo(ed) scheme
22215  this->reset_halo_haloed_scheme();
22216 
22217  // Get the number of elements in the mesh after load balance
22218  const unsigned nelement_after_load_balance = this->nelement();
22219 
22220  // We need to reset boundary elements because we need to get rid of
22221  // the old boundary elements and stay only with the new ones
22222  this->reset_boundary_element_info(ntmp_boundary_elements,
22223  ntmp_boundary_elements_in_region,
22224  deleted_elements);
22225 
22226  // There is no need to re-set boundary coordinates since the
22227  // load-balanced mesh already has the correct information (the
22228  // boundary coordinate for each node was sent with the node
22229  // information)
22230 
22231  // We need to re-compute the number of segments on each boundary
22232  // after load balance. It may be possible that the boundary is now
22233  // split in more segments, or that previous gaps between the
22234  // segments have now dissapeared because the received elements
22235  // filled those gaps
22236 
22237  // In order to re-set the number of segments it is required to get
22238  // the face elements, attach them to create a contiguous
22239  // representation of the boundary (in segments possibly) and then
22240  // counter the number of segments. This can only be done after
22241  // restoring the boundary elements scheme (which has been done
22242  // above)
22243 
22244  // Set the number of segments for the boundaries with geom objects
22245  // associated. The correct value is not on the original mesh since
22246  // it is computed only when calling then
22247  // setup_boundary_coordinates() method (called only for those
22248  // boundaries with no geom object associated)
22249  for (unsigned b = 0; b < tmp_nboundary; b++)
22250  {
22251  if (this->boundary_geom_object_pt(b)!=0)
22252  {
22253  // Clear the boundary segment nodes storage
22254  this->flush_boundary_segment_node(b);
22255 
22256  // Dummy vector of nodes on segments
22257  Vector<Vector<Node*> > dummy_segment_node_pt;
22258 
22259  // Compute the new number of segments in the boundary
22260  get_boundary_segment_nodes_helper(b, dummy_segment_node_pt);
22261 
22262  // Get the number of segments from the vector of nodes
22263  const unsigned nsegments = dummy_segment_node_pt.size();
22264 
22265  // Set the number of segments for the storing of the nodes
22266  // associated to the segments
22267  this->set_nboundary_segment_node(b, nsegments);
22268  } // if (this->boundary_geom_object_pt(b)!=0)
22269 
22270  } // for (b < n_boundary)
22271 
22272  // The time to re-establish the halo(ed) information
22273  if (Print_timings_level_load_balance>1)
22274  {
22275  oomph_info << "CPU for re-establishing halo(ed) information (load balance) [11]: "
22276  <<TimingHelpers::timer()-tt_start_re_etablish_halo_ed_info
22277  << std::endl;
22278  }
22279 
22280  // =====================================================================
22281  // END: REESTABLISH THE HALO(ED) SCHEME, ATTACH HALO ELEMENTS (HALO
22282  // NODES INCLUDED) TO THE NEW MESH (AFTER LOAD BALANCING) RESTORE
22283  // THE BOUNDARY ELEMENTS SCHEME AND THE NUMBER OF SEGMENTS ON EACH
22284  // BOUNDARY
22285  // =====================================================================
22286 
22287  if (Print_timings_level_load_balance>1)
22288  {
22289  oomph_info <<"CPU for load balance [n_ele_before="
22290  <<nelement_before_load_balance<<", n_ele_after="
22291  <<nelement_after_load_balance<<"]: "
22292  <<TimingHelpers::timer()-t_start_overall_load_balance
22293  << std::endl;
22294  }
22295 
22296  oomph_info << "Load balance (unstructured mesh) [END]" << std::endl;
22297 
22298  }
22299 
22300  //======================================================================
22301  /// Use the first and second group of elements to find the
22302  /// intersection between them to get the shared boundary
22303  /// elements from the first and second group
22304  //======================================================================
22305  template <class ELEMENT>
22308  const Vector<FiniteElement*> &first_element_pt,
22309  const Vector<FiniteElement*> &second_element_pt,
22310  Vector<FiniteElement*> &first_shared_boundary_element_pt,
22311  Vector<unsigned> &first_shared_boundary_element_face_index,
22312  Vector<FiniteElement*> &second_shared_boundary_element_pt,
22313  Vector<unsigned> &second_shared_boundary_element_face_index)
22314  {
22315  // 1) Compare their faces (nodes) and if they match then they are
22316  // part of a shared boundary
22317  // 2) Save the first and second group of elements that give rise to
22318  // the shared boundary, also include the face index
22319 
22320  // Get the number of elements on the first group
22321  const unsigned nfirst_element = first_element_pt.size();
22322  // Loop over the elements in the first group
22323  for (unsigned ef = 0; ef < nfirst_element; ef++)
22324  {
22325  // Get the element
22326  FiniteElement* fele_pt = first_element_pt[ef];
22327  // Check if the element is halo
22328  bool first_ele_is_halo = false;
22329  if (fele_pt->is_halo())
22330  {
22331  first_ele_is_halo = true;
22332  }
22333  // Get each of the faces
22334  for (unsigned ifface = 0; ifface < 3; ifface++)
22335  {
22336  Vector<Node*> first_face(2);
22337  if (ifface == 0)
22338  {
22339  first_face[0] = fele_pt->node_pt(1);
22340  first_face[1] = fele_pt->node_pt(2);
22341  }
22342  else if (ifface == 1)
22343  {
22344  first_face[0] = fele_pt->node_pt(2);
22345  first_face[1] = fele_pt->node_pt(0);
22346  }
22347  else if (ifface == 2)
22348  {
22349  first_face[0] = fele_pt->node_pt(0);
22350  first_face[1] = fele_pt->node_pt(1);
22351  }
22352 
22353  // Now check each of the faces with the faces on the second
22354  // elements
22355 
22356  // Get the number of elements on the second group
22357  const unsigned nsecond_element = second_element_pt.size();
22358  // Loop over the elements in the second group
22359  for (unsigned es = 0; es < nsecond_element; es++)
22360  {
22361  // Get the element
22362  FiniteElement* sele_pt = second_element_pt[es];
22363  // Check if the element is halo
22364  bool second_ele_is_halo = false;
22365  if (sele_pt->is_halo())
22366  {
22367  second_ele_is_halo = true;
22368  }
22369  // Now check whether both elements are halo, if that is the
22370  // case then we go for the next elements. We can not look for
22371  // shared boundaries between halo elements since other
22372  // processors, those with the nonhalo counterpart of the
22373  // elements, are in charge of creating those shared boundaries
22374  if (!(first_ele_is_halo && second_ele_is_halo))
22375  {
22376  // Get each of the faces
22377  for (unsigned isface = 0; isface < 3; isface++)
22378  {
22379  Vector<Node*> second_face(2);
22380  if (isface == 0)
22381  {
22382  second_face[0] = sele_pt->node_pt(1);
22383  second_face[1] = sele_pt->node_pt(2);
22384  }
22385  else if (isface == 1)
22386  {
22387  second_face[0] = sele_pt->node_pt(2);
22388  second_face[1] = sele_pt->node_pt(0);
22389  }
22390  else if (isface == 2)
22391  {
22392  second_face[0] = sele_pt->node_pt(0);
22393  second_face[1] = sele_pt->node_pt(1);
22394  }
22395 
22396  // Now check for any intersection among first and second
22397  // faces
22398  if (first_face[0] == second_face[0] &&
22399  first_face[1] == second_face[1])
22400  {
22401  // Save the elements on the corresponding containers
22402  first_shared_boundary_element_pt.push_back(fele_pt);
22403  // .. and the face index
22404  first_shared_boundary_element_face_index.push_back(ifface);
22405 
22406  // Save the elements on the corresponding containers
22407  second_shared_boundary_element_pt.push_back(sele_pt);
22408  // .. and the face index
22409  second_shared_boundary_element_face_index.push_back(isface);
22410 
22411  // Break the loop over the faces of the first elements
22412  // and the first elements, we need to continue looking
22413  // on the next face of the first elements
22414 
22415  // Increase the indexes to force breaking the loop
22416  isface = 3;
22417  es = nsecond_element;
22418 
22419  }
22420  // Check for intersection with the reversed case too
22421  else if (first_face[0] == second_face[1] &&
22422  first_face[1] == second_face[0])
22423  {
22424  // Save the elements on the corresponding containers
22425  first_shared_boundary_element_pt.push_back(fele_pt);
22426  // .. and the face index
22427  first_shared_boundary_element_face_index.push_back(ifface);
22428 
22429  // Save the elements on the corresponding containers
22430  second_shared_boundary_element_pt.push_back(sele_pt);
22431  // .. and the face index
22432  second_shared_boundary_element_face_index.push_back(isface);
22433 
22434  // Break the loop over the faces of the first elements
22435  // and the first elements, we need to continue looking
22436  // on the next face of the first elements
22437 
22438  // Increase the indexes to force breaking the loop
22439  isface = 3;
22440  es = nsecond_element;
22441  }
22442 
22443  } // for (isface < 3)
22444 
22445  } // if (!(first_ele_is_halo && second_ele_is_halo))
22446 
22447  } // for (es < nsecond_element)
22448 
22449  } // for (ifface < 3)
22450 
22451  } // for (ef < nfirst_element)
22452 
22453  }
22454 
22455  //======================================================================
22456  /// \short Creates the new shared boundaries, this method is also in
22457  /// charge of computing the shared boundaries ids of each processor
22458  /// and send that info. to all the processors
22459  //======================================================================
22460  template <class ELEMENT>
22462  create_new_shared_boundaries(std::set<FiniteElement*>
22463  &element_in_processor_pt,
22464  Vector<Vector<FiniteElement*> >
22465  &new_shared_boundary_element_pt,
22466  Vector<Vector<unsigned> >
22467  &new_shared_boundary_element_face_index)
22468  {
22469  // Get the number of processors
22470  const unsigned nproc = this->communicator_pt()->nproc();
22471  // Get the rank of the current processor
22472  const unsigned my_rank = this->communicator_pt()->my_rank();
22473 
22474  // ================================================================
22475  // BEGIN: GET THE SHARED BOUNDARY FACE ELEMENTS FROM THE SHARED
22476  // BOUNDARY ELEMENTS, AND ASSIGN A ROOT EDGE TO EACH FACE
22477  // ELEMENT. AVOID THE CREATION OF FACE ELEMENTS THAT REPRESENT THE
22478  // SAME EDGE (INTERNAL BOUNDARIES)
22479  // ================================================================
22480 
22481  // Get the time to get edges from shared boundary face elements
22482  double tt_start_get_edges_from_shd_bnd_face_ele=0.0;
22483  if (Print_timings_level_load_balance>2)
22484  {
22485  tt_start_get_edges_from_shd_bnd_face_ele=TimingHelpers::timer();
22486  }
22487 
22488  // Face elements that create the shared boundaries (unsorted)
22489  Vector<Vector<FiniteElement*> > tmp_unsorted_face_ele_pt(nproc);
22490  // The elements from where the face element was created
22491  Vector<Vector<FiniteElement*> > tmp_unsorted_ele_pt(nproc);
22492  // The face index of the bulk element from where was created the
22493  // face element
22494  Vector<Vector<int> > tmp_unsorted_face_index_ele(nproc);
22495 
22496  // Store the current edges lying on boundaries (this will help for
22497  // any edge of a shared boundary lying on an internal boundary)
22498  std::map<std::pair<Node*, Node*>, unsigned> elements_edges_on_boundary;
22499 
22500  // Compute the edges on the other boundaries
22501  this->get_element_edges_on_boundary(elements_edges_on_boundary);
22502 
22503  // Mark those edges (pair of nodes overlapped by a shared boundary)
22504  std::map<std::pair<Node*,Node*>, bool> overlapped_edge;
22505 
22506  // Associate every found edge (face element) on the shared boundary
22507  // with an original boundary only if the edge (face element) lies
22508  // (overlaps) on an original boundary, it may happen only for
22509  // internal boundaries
22510  Vector<Vector<int> > tmp_edge_boundary(nproc);
22511 
22512  // Get the face elements from the shared boundary elements with in
22513  // each processor
22514  for (unsigned iproc = 0; iproc < nproc; iproc++)
22515  {
22516  // There are no shared boundary elements with myself
22517  if (iproc != my_rank)
22518  {
22519  // Get the number of shared boundary elements with in "iproc"
22520  // processor
22521  const unsigned n_shared_bound_ele =
22522  new_shared_boundary_element_pt[iproc].size();
22523 
22524  // Avoid to create repeated face elements, compare the nodes on
22525  // the edges of the face elements
22526  Vector<std::pair<Node*, Node*> > done_faces;
22527 
22528  // Count the number of repeated faces
22529  unsigned nrepeated_faces = 0;
22530 
22531  // Loop over the shared boundary elements with the iproc
22532  // processor
22533  for (unsigned iele = 0; iele < n_shared_bound_ele; iele++)
22534  {
22535  // Get the bulk element
22536  FiniteElement* bulk_ele_pt =
22537  new_shared_boundary_element_pt[iproc][iele];
22538 
22539  // Get the face index
22540  int face_index =
22541  static_cast<int>(new_shared_boundary_element_face_index[iproc][iele]);
22542 
22543  // Create the face element
22544  FiniteElement* tmp_ele_pt =
22545  new DummyFaceElement<ELEMENT> (bulk_ele_pt, face_index);
22546 
22547  // Before adding the face element to the vector check that is
22548  // not has been previously created
22549  bool done_face = false;
22550 
22551  // Get the number of nodes on the face element and get the first
22552  // and last node
22553  const unsigned nnode_face_ele = tmp_ele_pt->nnode();
22554  Node* first_face_node_pt = tmp_ele_pt->node_pt(0);
22555  Node* last_face_node_pt = tmp_ele_pt->node_pt(nnode_face_ele - 1);
22556 
22557  // Get the number of already done face elements
22558  const unsigned ndone_faces = done_faces.size();
22559  // Loop over the already visited face elements
22560  for (unsigned n = 0; n < ndone_faces; n++)
22561  {
22562  Node* first_done_face_node_pt = done_faces[n].first;
22563  Node* second_done_face_node_pt = done_faces[n].second;
22564  if (first_face_node_pt == first_done_face_node_pt &&
22565  last_face_node_pt == second_done_face_node_pt)
22566  {
22567  done_face = true;
22568  nrepeated_faces++;
22569  break;
22570  }
22571  // Check for the reversed case
22572  else if (first_face_node_pt == second_done_face_node_pt &&
22573  last_face_node_pt == first_done_face_node_pt)
22574  {
22575  done_face = true;
22576  nrepeated_faces++;
22577  break;
22578  }
22579 
22580  } // for (n < ndone_faces)
22581 
22582  // Only include the faces that are not repeated
22583  if (!done_face)
22584  {
22585  // Add the face element in the vector
22586  tmp_unsorted_face_ele_pt[iproc].push_back(tmp_ele_pt);
22587  // Add the bulk element to the vector
22588  tmp_unsorted_ele_pt[iproc].push_back(bulk_ele_pt);
22589  // Add the face index to the vector
22590  tmp_unsorted_face_index_ele[iproc].push_back(face_index);
22591  // Include the nodes in the done nodes vector
22592  std::pair<Node*, Node*> tmp_edge =
22593  std::make_pair(first_face_node_pt, last_face_node_pt);
22594  // Push the edge
22595  done_faces.push_back(tmp_edge);
22596 
22597  // Associate the face element with a boundary (if that is
22598  // the case)
22599  int edge_boundary_id = -1;
22600  std::map<std::pair<Node*,Node*>, unsigned >::iterator it;
22601  it = elements_edges_on_boundary.find(tmp_edge);
22602  // If the edges lie on a boundary then get the boundary id
22603  // on which the edges lie
22604  if (it != elements_edges_on_boundary.end())
22605  {
22606  // Assign the internal boundary id associated with the
22607  // edge
22608  edge_boundary_id = (*it).second;
22609  // Mark the edge as overlapped
22610  overlapped_edge[tmp_edge] = true;
22611  // Also include the reversed version of the edge
22612  std::pair<Node*, Node*> rev_tmp_edge =
22613  std::make_pair(last_face_node_pt, first_face_node_pt);
22614  // Mark the reversed version of the edge as overlapped
22615  overlapped_edge[rev_tmp_edge] = true;
22616  }
22617  else
22618  {
22619  // Look for the reversed version
22620  std::pair<Node*,Node*> rtmp_edge =
22621  std::make_pair(last_face_node_pt, first_face_node_pt);
22622  it = elements_edges_on_boundary.find(rtmp_edge);
22623  if (it != elements_edges_on_boundary.end())
22624  {
22625  // Assign the internal boundary id associated with the
22626  // edge
22627  edge_boundary_id = (*it).second;
22628  // Mark the edge as overlapped
22629  overlapped_edge[rtmp_edge] = true;
22630  // Mark the reversed version (normal) of the edge as
22631  // overlapped
22632  overlapped_edge[tmp_edge] = true;
22633  }
22634  }
22635  // Associate the edge with a boundary
22636  tmp_edge_boundary[iproc].push_back(edge_boundary_id);
22637  } // if (!done_face)
22638  else
22639  {
22640  // Delete the repeated face elements
22641  delete tmp_ele_pt;
22642  tmp_ele_pt = 0;
22643  }
22644 
22645  } // for (iele < n_shared_bound_ele)
22646 
22647  } // if (iproc != my_rank)
22648 
22649  } // for (iproc < nproc)
22650 
22651  // The time to get edges from shared boundary face elements
22652  if (Print_timings_level_load_balance>2)
22653  {
22654  oomph_info << "CPU for getting edges from shared boundary face elements (load balance) [9.1]: "
22655  <<TimingHelpers::timer()-tt_start_get_edges_from_shd_bnd_face_ele
22656  << std::endl;
22657  }
22658 
22659  // ================================================================
22660  // END: GET THE SHARED BOUNDARY FACE ELEMENTS FROM THE SHARED
22661  // BOUNDARY ELEMENTS, AND ASSIGN A ROOT EDGE TO EACH FACE
22662  // ELEMENT. AVOID THE CREATION OF FACE ELEMENTS THAT REPRESENT THE
22663  // SAME EDGE (INTERNAL BOUNDARIES)
22664  // ================================================================
22665 
22666  // ================================================================
22667  // BEGIN: BEFORE SORTING THE SHARED FACE ELEMENTS AND ITS ASSOCIATED
22668  // DATA, WE NEED TO ENSURE THAT THEY APPEAR (OR ARE STORED) IN THE
22669  // SAME ORDER IN BOTH OF THE PROCESSORS THAT CREATED THEM. WE USE
22670  // THE BOTTOM-LEFT NODE OF EACH FACE ELEMENT TO STORE THEM IN THE
22671  // SAME ORDER IN BOTH PROCESSORS. ALSO ENSURE THAT THE FACE ELEMENTS
22672  // AGREE WITH THE FIRST AND LAST NODE IN ALL PROCESSORS
22673  // ================================================================
22674 
22675  // Get the time to sort shared face elements
22676  double tt_start_sort_shared_face_elements=0.0;
22677  if (Print_timings_level_load_balance>2)
22678  {
22679  tt_start_sort_shared_face_elements=TimingHelpers::timer();
22680  }
22681 
22682  // -----------------------------------------------------------------
22683  // Before continuing we need to ensured that the face elements are
22684  // stored in the same order in all processors. Sort them starting
22685  // from the face element with the bottom-left node coordinate
22686 
22687  // Face elements that create the shared boundaries (unsorted)
22688  Vector<Vector<FiniteElement*> > unsorted_face_ele_pt(nproc);
22689  // The elements from where the face element was created
22690  Vector<Vector<FiniteElement*> > unsorted_ele_pt(nproc);
22691  // The face index of the bulk element from where was created the
22692  // face element
22693  Vector<Vector<int> > unsorted_face_index_ele(nproc);
22694  // Associate every found edge on the shared boundary with an
22695  // original boundary only if the edge lies on an original boundary,
22696  // it may happen only for internal boundaries
22697  Vector<Vector<int> > edge_boundary(nproc);
22698 
22699  // For each face element, mark if the element should be considered
22700  // in its inverted way to fullfill with the bottom-left node to be
22701  // the first (left) node. First get the status of each element and
22702  // when they get sorted copy the values across
22703  std::vector<std::vector<bool> > tmp_treat_as_inverted(nproc);
22704  // Vector to store the status of the sorted face elements based on
22705  // the bottom-left condition
22706  std::vector<std::vector<bool> > treat_as_inverted(nproc);
22707 
22708  // Get the bottom-left node of each face element and sort them
22709  // starting from the face element with the bottom-left node
22710 
22711  // Loop over the processors
22712  for (unsigned iproc = 0; iproc < nproc; iproc++)
22713  {
22714  // There are no shared face elements with myself
22715  if (iproc != my_rank)
22716  {
22717  // Get the number of unsorted face elements
22718  const unsigned n_face_ele = tmp_unsorted_face_ele_pt[iproc].size();
22719  // Store the centroid of the face element. Perform the sorting
22720  // based on the bottom-left centroid of each face element
22721  Vector<Vector<double> > centroid_vertices(n_face_ele);
22722 
22723  // Resize the storage for the treating as inverted face element
22724  // storage
22725  tmp_treat_as_inverted[iproc].resize(n_face_ele);
22726 
22727  // Loop over the face elements associated with the iproc
22728  // processor
22729  for (unsigned e = 0; e < n_face_ele; e++)
22730  {
22731  // Get the face element
22732  FiniteElement* face_ele_pt = tmp_unsorted_face_ele_pt[iproc][e];
22733  // Get the number of nodes of the face element
22734  const unsigned n_node = face_ele_pt->nnode();
22735  Vector<double> bottom_left(2);
22736  // Assign as the bottom-left node the first node
22737  // Get the node
22738  Node* node_pt = face_ele_pt->node_pt(0);
22739  bottom_left[0] = node_pt->x(0);
22740  bottom_left[1] = node_pt->x(1);
22741  // Set as not treat as inverted element
22742  tmp_treat_as_inverted[iproc][e] = false;
22743  // Loop over the nodes to get the bottom-left vertex of all
22744  // the nodes
22745  for (unsigned n = 1; n < n_node; n++)
22746  {
22747  // Get the node
22748  Node* node_pt = face_ele_pt->node_pt(n);
22749  if (node_pt->x(1) < bottom_left[1])
22750  {
22751  bottom_left[0] = node_pt->x(0);
22752  bottom_left[1] = node_pt->x(1);
22753  // The first node is no longer the bottom-left node, we
22754  // need to treat the element as inverted
22755  tmp_treat_as_inverted[iproc][e] = true;
22756  } // if (node_pt->x(1) < bottom_left[1])
22757  else if (node_pt->x(1) == bottom_left[1])
22758  {
22759  if (node_pt->x(0) < bottom_left[0])
22760  {
22761  bottom_left[0] = node_pt->x(0);
22762  bottom_left[1] = node_pt->x(1);
22763  // The first node is no longer the bottom-left node, we
22764  // need to treat the element as inverted
22765  tmp_treat_as_inverted[iproc][e] = true;
22766  } // if (node_pt->x(0) < bottom_left[0])
22767  } // else if (node_pt->x(1) == bottom_left[1])
22768 
22769  } // for (n < n_node
22770 
22771  // Resize the container
22772  centroid_vertices[e].resize(2);
22773  // Add the centroid of the face element
22774  centroid_vertices[e][0] =
22775  (face_ele_pt->node_pt(0)->x(0) +
22776  face_ele_pt->node_pt(n_node-1)->x(0))*0.5;
22777  centroid_vertices[e][1] =
22778  (face_ele_pt->node_pt(0)->x(1) +
22779  face_ele_pt->node_pt(n_node-1)->x(1))*0.5;
22780 
22781  } // for (e < n_face_ele)
22782 
22783  // Sort the face elements based on their bottom-left node
22784  unsigned n_sorted_bottom_left = 0;
22785  // Keep track of the already sorted face elements
22786  std::vector<bool> done_face(n_face_ele, false);
22787 
22788  // Loop until all face elements have been sorted
22789  while (n_sorted_bottom_left < n_face_ele)
22790  {
22791  // The index of the next bottom-left face element
22792  unsigned index = 0;
22793  Vector<double> current_bottom_left(2);
22794  for (unsigned e = 0; e < n_face_ele; e++)
22795  {
22796  // Get the first not done face element
22797  if (!done_face[e])
22798  {
22799  // Store the first not done
22800  current_bottom_left[0] = centroid_vertices[e][0];
22801  current_bottom_left[1] = centroid_vertices[e][1];
22802  // Set the index
22803  index = e;
22804  // Break
22805  break;
22806  } // if (!done_face[e])
22807 
22808  } // for (e < n_face_ele)
22809 
22810  // Loop over all the other nondone face elements
22811  for (unsigned e = index + 1; e < n_face_ele; e++)
22812  {
22813  // Get the first not done face element
22814  if (!done_face[e])
22815  {
22816  if (centroid_vertices[e][1] < current_bottom_left[1])
22817  {
22818  // Re-set the current bottom left vertex
22819  current_bottom_left[0] = centroid_vertices[e][0];
22820  current_bottom_left[1] = centroid_vertices[e][1];
22821  // Re-assign the index
22822  index = e;
22823  } // if (centroid_vertices[e][1] < current_bottom_left[1])
22824  else if (centroid_vertices[e][1] == current_bottom_left[1])
22825  {
22826  if (centroid_vertices[e][0] < current_bottom_left[0])
22827  {
22828  // Re-set the current bottom left vertex
22829  current_bottom_left[0] = centroid_vertices[e][0];
22830  current_bottom_left[1] = centroid_vertices[e][1];
22831  // Re-assign the index
22832  index = e;
22833  } // if (centroid_vertices[e][0] < current_bottom_left[0])
22834 
22835  } // else if (centroid_vertices[e][1] == current_bottom_left[1])
22836 
22837  } // if (!done_face[e])
22838 
22839  } // for (e < n_face_ele)
22840 
22841  // The face element
22842  unsorted_face_ele_pt[iproc].
22843  push_back(tmp_unsorted_face_ele_pt[iproc][index]);
22844  // The boundary element
22845  unsorted_ele_pt[iproc].
22846  push_back(tmp_unsorted_ele_pt[iproc][index]);
22847  // The face index
22848  unsorted_face_index_ele[iproc].
22849  push_back(tmp_unsorted_face_index_ele[iproc][index]);
22850  // The edge boundary associated to the face element
22851  edge_boundary[iproc].
22852  push_back(tmp_edge_boundary[iproc][index]);
22853  // The treat as inverted condition
22854  treat_as_inverted[iproc].
22855  push_back(tmp_treat_as_inverted[iproc][index]);
22856 
22857  // Mark the face element as sorted (done or visited)
22858  done_face[index] = true;
22859 
22860  // Increase the number of sorted bottom-left face elements
22861  n_sorted_bottom_left++;
22862 
22863  } // while (n_sorted_bottom_left < n_face_ele)
22864 
22865 #ifdef PARANOID
22866  // Get the number of face elements sorted with the bottom-left
22867  // condition
22868  const unsigned tmp_n_face_ele = unsorted_face_ele_pt[iproc].size();
22869 
22870  if (tmp_n_face_ele != n_face_ele)
22871  {
22872  std::ostringstream error_stream;
22873  error_stream
22874  << "The number of face elements before sorting them starting\n"
22875  << "from their bottom-left vertex is different from the number\n"
22876  << "of face elements after the sorting\n"
22877  << "N. ele before sorting: (" << n_face_ele << ")\n"
22878  << "N. ele after sorting: (" << tmp_n_face_ele << ")\n";
22879  throw OomphLibError(error_stream.str(),
22880  "RefineableTriangleMesh::create_new_shared_boundaries()",
22881  OOMPH_EXCEPTION_LOCATION);
22882  }
22883 #endif
22884 
22885  } // if (iproc != my_rank)
22886 
22887  } // for (iproc < nproc)
22888 
22889  // The time to sort shared face elements
22890  if (Print_timings_level_load_balance>2)
22891  {
22892  oomph_info << "CPU for sorting shared boundary face elements (load balance) [9.2]: "
22893  <<TimingHelpers::timer()-tt_start_sort_shared_face_elements
22894  << std::endl;
22895  }
22896 
22897  // ================================================================
22898  // END: SORTING THE SHARED FACE ELEMENTS AND ITS ASSOCIATED DATA, WE
22899  // NEED TO ENSURE THAT THEY APPEAR (OR ARE STORED) IN THE SAME ORDER
22900  // IN BOTH OF THE PROCESSORS THAT CREATED THEM. WE USE THE
22901  // BOTTOM-LEFT NODE OF EACH FACE ELEMENT TO STORE THEM IN THE SAME
22902  // ORDER IN BOTH PROCESSORS. ALSO ENSURE THAT THE FACE ELEMENTS
22903  // AGREE WITH THE FIRST AND LAST NODE IN ALL PROCESSORS
22904  // ================================================================
22905 
22906  // ================================================================
22907  // BEGIN: COMPUTE THE GLOBAL DEGREE (VALENCY OF EACH NODE). THE
22908  // DEGREE OF THE NODES IN THE CURRENT SHARED BOUNDARIES IS COMPUTED
22909  // FIRST, THEN THIS INFO. IS SENT TO A ROOT PROCESSOR WHICH IS IN
22910  // CHARGE OF IDENTIFY AND RE-ASSIGN THE DEGREE OF THE NODES (IF THAT
22911  // IS THE CASE)
22912  // ================================================================
22913 
22914  // Get the time to compute the valency of each node
22915  double tt_start_compute_valency_of_nodes=0.0;
22916  if (Print_timings_level_load_balance>2)
22917  {
22918  tt_start_compute_valency_of_nodes=TimingHelpers::timer();
22919  }
22920 
22921  // Stores the global-degree of each node
22922  std::map<Node*, unsigned> global_node_degree;
22923 
22924  // Get the global degree (valency) of each node
22925  compute_shared_node_degree_helper(unsorted_face_ele_pt,
22926  global_node_degree);
22927 
22928  // The time to compute the valency of each node
22929  if (Print_timings_level_load_balance>2)
22930  {
22931  oomph_info << "CPU for computing the valency of nodes (load balance) [9.3]: "
22932  <<TimingHelpers::timer()-tt_start_compute_valency_of_nodes
22933  << std::endl;
22934  }
22935 
22936  // ================================================================
22937  // END: COMPUTE THE GLOBAL DEGREE (VALENCY OF EACH NODE). THE
22938  // DEGREE OF THE NODES IN THE CURRENT SHARED BOUNDARIES IS COMPUTED
22939  // FIRST, THEN THIS INFO. IS SENT TO A ROOT PROCESSOR WHICH IS IN
22940  // CHARGE OF IDENTIFY AND RE-ASSIGN THE DEGREE OF THE NODES (IF THAT
22941  // IS THE CASE)
22942  // ================================================================
22943 
22944  // ================================================================
22945  // BEGIN: IDENTIFY THE NODES LYING ON EDGES NOT OVERLAPED BY SHARED
22946  // BOUNDARIES, IDENTIFY THE BOUNDARY TO WHICH THE EDGE CORRESPOND
22947  // ================================================================
22948 
22949  // Get the time to compute nodes on non overlapped shared boundaries
22950  double tt_start_nodes_on_non_overlapped_shd_bnd=0.0;
22951  if (Print_timings_level_load_balance>2)
22952  {
22953  tt_start_nodes_on_non_overlapped_shd_bnd=TimingHelpers::timer();
22954  }
22955 
22956  // Mark the nodes on original boundaries not overlapped by shared
22957  // boundaries
22958  std::map<unsigned, std::map<Node*, bool> >
22959  node_on_bnd_not_overlapped_by_shd_bnd;
22960 
22961  // Loop over the edges of the original boundaries
22962  for (std::map<std::pair<Node*,Node*>, unsigned>::iterator it_map =
22963  elements_edges_on_boundary.begin();
22964  it_map != elements_edges_on_boundary.end(); it_map++)
22965  {
22966  // Get the edge
22967  std::pair<Node*,Node*> edge_pair = (*it_map).first;
22968  // Is the edge overlaped by a shared boundary
22969  if (!overlapped_edge[edge_pair])
22970  {
22971  // Mark the nodes of the edge as being on an edge not overlaped
22972  // by a shared boundary on the boundary the edge is
22973  unsigned b = (*it_map).second;
22974 
22975  // Get the left node
22976  Node* left_node_pt = edge_pair.first;
22977  node_on_bnd_not_overlapped_by_shd_bnd[b][left_node_pt] = true;
22978 
22979  // Get the right node
22980  Node* right_node_pt = edge_pair.second;
22981  node_on_bnd_not_overlapped_by_shd_bnd[b][right_node_pt] = true;
22982 
22983  } // if (!overlapped_edge[edge_pair])
22984 
22985  } // Loop over edges to mark those nodes on overlaped edge by
22986  // shared boundaries
22987 
22988  // The time to compute nodes on non overlapped shared boundaries
22989  if (Print_timings_level_load_balance>2)
22990  {
22991  oomph_info << "CPU for computing nodes on non overlapped shared boundaries (load balance) [9.4]: "
22992  <<TimingHelpers::timer()-tt_start_nodes_on_non_overlapped_shd_bnd
22993  << std::endl;
22994  }
22995 
22996  // ================================================================
22997  // END: IDENTIFY THE NODES LYING ON EDGES NOT OVERLAPED BY SHARED
22998  // BOUNDARIES, IDENTIFY THE BOUNDARY TO WHICH THE EDGE CORRESPOND
22999  // ================================================================
23000 
23001  // ==================================================================
23002  // BEGIN: SORT THE SHARED BOUNDARY FACE ELEMENTS, ADD FACE ELEMENTS
23003  // TO THE LEFT OR RIGHT OF THE ROOT FACE ELEMENT. STOP ADDING WHEN
23004  // THE MOST LEFT OR MOST RIGHT ELEMENT (NODE) IS ALREADY PART OF
23005  // ANOTHER BOUNDARY (THIS MEANS THAT THE SHARED BOUNDARY THAT IS
23006  // BEING CREATED HAS A CONNECTION). ALSO REMEMBER TO CHECK FOR THE
23007  // CASE WHEN THE MOST LEFT OR MOST RIGHT NODE IS A BOUNDARY NODE OF
23008  // A BOUNDARY THAT NO LONGER EXIST IN THE DOMAIN. AT THE END OF THIS
23009  // SECTION WE WILL HAVE THE NUMBER OF SHARED BOUNDARIES OF THIS
23010  // PROCESSOR WITH OTHERS BUT NOT THE GLOBAL SHARED BOUNDARY ID
23011  // ==================================================================
23012 
23013  // Get the time to sort shared boundaries face elements to create a
23014  // continuous representation of the boundary
23015  double tt_start_join_shd_bnd_face_ele=0.0;
23016  if (Print_timings_level_load_balance>2)
23017  {
23018  tt_start_join_shd_bnd_face_ele=TimingHelpers::timer();
23019  }
23020 
23021  // Face elements that create the shared boundaries (sorted)
23022  Vector<Vector<Vector<FiniteElement*> > > sorted_face_ele_pt(nproc);
23023 
23024  // Bulk elements that create the shared boundaries (sorted)
23025  Vector<Vector<Vector<FiniteElement*> > > sorted_ele_pt(nproc);
23026 
23027  // Face indexes of the bulk elements that create the shared
23028  // boundaries (sorted)
23029  Vector<Vector<Vector<int> > > sorted_face_index_ele(nproc);
23030 
23031  // Store the edge boundary id associated with a shared boundary (if
23032  // any, this apply for shared boundaries lying on internal
23033  // boundaries, then the shared boundary is marked as overlaping an
23034  // internal boundary)
23035  Vector<Vector<int> > edge_boundary_id(nproc);
23036 
23037  // Store the connection information obtained when joining the face
23038  // elements (used for connection purposes only)
23039  Vector<Vector<Vector<int> > > sorted_connection_info(nproc);
23040 
23041  // Store the local shared boundary id associated to the elements
23042  // that will give rise to the shared boundaries (used to compute the
23043  // global shared boundary id from the local shared boundary id)
23044  Vector<Vector<unsigned> > proc_local_shared_boundary_id(nproc);
23045 
23046  // Map that associates the local shared boundary id with the list of
23047  // nodes that create it
23048  std::map<unsigned, std::list<Node*> >
23049  local_shd_bnd_id_to_sorted_list_node_pt;
23050 
23051  // Local shared bouonday id (used to locally identify the lists of
23052  // nodes that create shared boundaries, it is also useful to
23053  // identify connections with shared boundaries)
23054  unsigned local_shd_bnd_id = this->Initial_shared_boundary_id;
23055 
23056  // Sort the face elements, using the nodes at its ends
23057 
23058  // Mark the done elements
23059  std::map<FiniteElement*, bool> done_ele;
23060 
23061  // Mark the inverted elements
23062  std::map<FiniteElement*, bool> is_inverted;
23063 
23064  // Sort the face elements to get the number of shared boundaries
23065  // with in each processor
23066  for (unsigned iproc = 0; iproc < nproc; iproc++)
23067  {
23068  // No face elements with myself
23069  if (iproc != my_rank)
23070  {
23071  // Get the number of unsorted face elements with the iproc
23072  // processor
23073  const unsigned nunsorted_face_ele =
23074  unsorted_face_ele_pt[iproc].size();
23075  // Count the number of sorted face elements
23076  unsigned nsorted_face_ele = 0;
23077 
23078  // Iterate until all the face elements have been sorted
23079  while (nsorted_face_ele < nunsorted_face_ele)
23080  {
23081  // Take the first nonsorted element an use it as root element,
23082  // add elements to the left and right until no more elements
23083  // left or until a stop condition is reached (connection,
23084  // boundary node)
23085 
23086 #ifdef PARANOID
23087  // Flag to indicate if a root element was found
23088  bool found_root_element = false;
23089 #endif
23090 
23091  // Index of the found root element
23092  unsigned root_index = 0;
23093 
23094  // List that contains the sorted face elements
23095  std::list<FiniteElement*> tmp_sorted_face_ele_pt;
23096 
23097  // List that contains the sorted elements
23098  std::list<FiniteElement*> tmp_sorted_ele_pt;
23099 
23100  // List that contains the sorted face indexes of the bulk
23101  // elements
23102  std::list<int> tmp_sorted_face_index_ele;
23103 
23104  // Storing for the sorting nodes extracted from the face
23105  // elements. The sorted nodes are used to identify connections
23106  // among new shared boundaries or original boundaries
23107  std::list<Node*> tmp_sorted_nodes_pt;
23108  // Clear the storage (just in case)
23109  tmp_sorted_nodes_pt.clear();
23110 
23111  // The initial and final nodes
23112  Node* initial_node_pt = 0;
23113  Node* final_node_pt = 0;
23114 
23115  // Store the original boundary id related with the root face
23116  // element (if there is one)
23117  int root_edge_bound_id = -1;
23118 
23119  // Loop over the unsorted face elements until a root element
23120  // is found
23121  for (unsigned e = 0; e < nunsorted_face_ele; e++)
23122  {
23123  // Get a root element
23124  FiniteElement* root_ele_pt = unsorted_face_ele_pt[iproc][e];
23125  // Is the element already done?
23126  if (!done_ele[root_ele_pt])
23127  {
23128  // Get the edge boundary id associated with the edge (if
23129  // there is one)
23130  root_edge_bound_id = edge_boundary[iproc][e];
23131  // Add the face element to the list of sorted face
23132  // elements
23133  tmp_sorted_face_ele_pt.push_back(root_ele_pt);
23134  // Add the bulk element to the list of sorted elements
23135  tmp_sorted_ele_pt.push_back(unsorted_ele_pt[iproc][e]);
23136  // Add the face index to the list of sorted face index
23137  // elements
23138  tmp_sorted_face_index_ele.push_back(
23139  unsorted_face_index_ele[iproc][e]);
23140 
23141  // Get the nodes and state them as initial and final
23142  const unsigned nnodes = root_ele_pt->nnode();
23143  // Check if the face element should be treated as inverted
23144  if (!treat_as_inverted[iproc][e])
23145  {
23146  initial_node_pt = root_ele_pt->node_pt(0);
23147  final_node_pt = root_ele_pt->node_pt(nnodes-1);
23148  }
23149  else
23150  {
23151  initial_node_pt = root_ele_pt->node_pt(nnodes-1);
23152  final_node_pt = root_ele_pt->node_pt(0);
23153  }
23154  // Add both nodes to the list of sorted nodes
23155  tmp_sorted_nodes_pt.push_back(initial_node_pt);
23156  tmp_sorted_nodes_pt.push_back(final_node_pt);
23157 
23158  // Mark the element as done
23159  done_ele[root_ele_pt] = true;
23160  // Check if the face element should be treated as inverted
23161  if (!treat_as_inverted[iproc][e])
23162  {
23163  // Mark the element as not inverted
23164  is_inverted[root_ele_pt] = false;
23165  }
23166  else
23167  {
23168  // Mark the element as inverted
23169  is_inverted[root_ele_pt] = true;
23170  }
23171  // Increase the counter for sorted face elements
23172  nsorted_face_ele++;
23173  // Set the root index
23174  root_index = e;
23175 #ifdef PARANOID
23176  // Set the flag of found root element
23177  found_root_element = true;
23178 #endif
23179  // Break the loop
23180  break;
23181 
23182  } // if (!done_ele[root_ele_pt])
23183 
23184  } // for (e < nunsorted_face_ele)
23185 
23186 #ifdef PARANOID
23187  if (!found_root_element)
23188  {
23189  std::ostringstream error_stream;
23190  error_stream
23191  << "It was not possible the found the root element\n\n";
23192  throw OomphLibError(error_stream.str(),
23193  OOMPH_CURRENT_FUNCTION,
23194  OOMPH_EXCEPTION_LOCATION);
23195  }
23196 #endif
23197 
23198  // New element added. Continue adding elements -- or nodes --
23199  // to the list of shared boundary elements while a new element
23200  // has been added to the list (we have just added the root
23201  // element)
23202  bool new_element_added = true;
23203 
23204  // Similarly that in the
23205  // "create_polylines_from_halo_elements_helper() method, we
23206  // extract the nodes (in order) that will create the shared
23207  // polyline, and also check for connections with the just
23208  // added face elements (nodes)
23209 
23210  // Flags to indicate at which end (of the sorted list of
23211  // boundary elements) the element was added (left or right)
23212  bool element_added_to_the_left = false;
23213  bool element_added_to_the_right = false;
23214 
23215  // Flag to indicate that the "left" node of the element added
23216  // to the left was found to be shared with another boundary
23217  bool connection_to_the_left = false;
23218 
23219  // Flag to indicate that the "right" node of the element added
23220  // to the right was found to be shared with another boundary
23221  bool connection_to_the_right = false;
23222 
23223  // Flag to stop the adding of elements (and nodes) to the
23224  // current shared boundary (because there are connections at
23225  // both ends)
23226  bool current_polyline_has_connections_at_both_ends = false;
23227 
23228  // Store the boundary ids of the polylines to connect (only
23229  // used when the polyline was found to have a connection)
23230  // -1: Indicates no connection
23231  // -2: Indicates connection with itself
23232  // -3: Indicates no connection BUT STOP adding elements
23233  // -because the node is a boundary node whose boundary is no
23234  // -currently part of the domain. Think in one of the corner
23235  // -nodes of a triangle touchin a boundary that does no longer
23236  // -exist
23237  // Any other value: Boundary id to connect
23238  int bound_id_connection_to_the_left = -1;
23239  int bound_id_connection_to_the_right = -1;
23240 
23241  // Get the global degree of the node (notice the local degree
23242  // has been updated to global degree)
23243  const unsigned initial_node_degree =
23244  global_node_degree[initial_node_pt];
23245 
23246  // Flag to indicate we are calling the method from a load
23247  // balance sub-rutine
23248  const bool called_for_load_balance=true;
23249 
23250  // Check if the nodes of the root element have connections
23251  // ... to the left
23252  bound_id_connection_to_the_left =
23253  this->check_connections_of_polyline_nodes(
23254  element_in_processor_pt,
23255  root_edge_bound_id,
23256  overlapped_edge,
23257  node_on_bnd_not_overlapped_by_shd_bnd,
23258  tmp_sorted_nodes_pt,
23259  local_shd_bnd_id_to_sorted_list_node_pt,
23260  initial_node_degree,
23261  initial_node_pt,
23262  called_for_load_balance);
23263 
23264  // If there is a stop condition then set the corresponding
23265  // flag
23266  if (bound_id_connection_to_the_left != -1)
23267  {
23268  connection_to_the_left = true;
23269  } // if (bound_id_connection_to_the_left != -1)
23270 
23271  // Get the global degree of the node (notice the local degree
23272  // has been updated to global degree)
23273  const unsigned final_node_degree =
23274  global_node_degree[final_node_pt];
23275 
23276  // ... and to the right
23277  bound_id_connection_to_the_right =
23278  this->check_connections_of_polyline_nodes(
23279  element_in_processor_pt,
23280  root_edge_bound_id,
23281  overlapped_edge,
23282  node_on_bnd_not_overlapped_by_shd_bnd,
23283  tmp_sorted_nodes_pt,
23284  local_shd_bnd_id_to_sorted_list_node_pt,
23285  final_node_degree,
23286  final_node_pt,
23287  called_for_load_balance);
23288 
23289  // If there is a stop condition then set the corresponding
23290  // flag
23291  if (bound_id_connection_to_the_right != -1)
23292  {
23293  connection_to_the_right = true;
23294  } // if (bound_id_connection_to_the_right != -1)
23295 
23296  // If the current shared boundary has connections at both ends
23297  // then stop the adding of elements (and nodes)
23298  if (connection_to_the_left && connection_to_the_right)
23299  {current_polyline_has_connections_at_both_ends = true;}
23300 
23301  // Continue searching for more elements to add if
23302  // 1) A new element was added at the left or right of the list
23303  // 2) There are more possible elements to add
23304  // 3) The nodes at the edges of the added element (left or
23305  // right) are not part of any other previous shared
23306  // boundary
23307  while(new_element_added &&
23308  (nsorted_face_ele < nunsorted_face_ele)
23309  && !current_polyline_has_connections_at_both_ends)
23310  {
23311  // Loop over the remaining elements and try to create a
23312  // contiguous set of face elements, start looking from the
23313  // root index. Any previous element should have been already
23314  // visited
23315  for (unsigned e = root_index; e < nunsorted_face_ele; e++)
23316  {
23317  // Reset the flags for added elements, to the left and right
23318  new_element_added = false;
23319  element_added_to_the_left = false;
23320  element_added_to_the_right = false;
23321 
23322  // Get the "e"-th element on the vector
23323  FiniteElement* tmp_ele_pt = unsorted_face_ele_pt[iproc][e];
23324  // Get the boundary id associated with the edge (if any)
23325  const int edge_bound_id = edge_boundary[iproc][e];
23326  // Check if the element has been already sorted and the
23327  // related edge bound id is the same as the root edge (if
23328  // any)
23329  if (!done_ele[tmp_ele_pt]
23330  && (edge_bound_id == root_edge_bound_id))
23331  {
23332  // Get the number of nodes on the current element
23333  const unsigned nnodes = tmp_ele_pt->nnode();
23334  // Get the first and last node of the element
23335  // Check if the face element should be treated as inverted
23336  Node* first_node_pt = 0;
23337  Node* last_node_pt = 0;
23338  if (!treat_as_inverted[iproc][e])
23339  {
23340  first_node_pt = tmp_ele_pt->node_pt(0);
23341  last_node_pt = tmp_ele_pt->node_pt(nnodes-1);
23342  }
23343  else
23344  {
23345  first_node_pt = tmp_ele_pt->node_pt(nnodes-1);
23346  last_node_pt = tmp_ele_pt->node_pt(0);
23347  }
23348 
23349  // A pointer to the node at the left or right of the
23350  // just added element, the most left or the most right
23351  // node
23352  Node* new_added_node_pt = 0;
23353 
23354  // Check if the element goes to the left
23355  if (initial_node_pt == last_node_pt &&
23356  !connection_to_the_left)
23357  {
23358  // Update the initial node and the just added node
23359  new_added_node_pt = initial_node_pt = first_node_pt;
23360  // Add the most left node
23361  tmp_sorted_nodes_pt.push_front(first_node_pt);
23362  // Add the face element to the list of sorted face
23363  // elements
23364  tmp_sorted_face_ele_pt.push_front(tmp_ele_pt);
23365  // Add the bulk element to the list of sorted elements
23366  tmp_sorted_ele_pt.push_front(unsorted_ele_pt[iproc][e]);
23367  // Add the face index to the list of sorted face index
23368  // elements
23369  tmp_sorted_face_index_ele.push_front(
23370  unsorted_face_index_ele[iproc][e]);
23371  if (!treat_as_inverted[iproc][e])
23372  {
23373  // Mark the element as not inverted
23374  is_inverted[tmp_ele_pt] = false;
23375  }
23376  else
23377  {
23378  // Mark the element as inverted
23379  is_inverted[tmp_ele_pt] = true;
23380  }
23381  // Set the flag to indicate a new element was added
23382  new_element_added = true;
23383  // Set the flag to indicate the element was added to
23384  // the left
23385  element_added_to_the_left = true;
23386  }
23387  // Check if the element goes to the left (but inverted)
23388  else if (initial_node_pt == first_node_pt &&
23389  !connection_to_the_left)
23390  {
23391  // Update the initial node and the just added node
23392  new_added_node_pt = initial_node_pt = last_node_pt;
23393  // Add the most left node
23394  tmp_sorted_nodes_pt.push_front(last_node_pt);
23395  // Add the face element to the list of sorted face
23396  // elements
23397  tmp_sorted_face_ele_pt.push_front(tmp_ele_pt);
23398  // Add the bulk element to the list of sorted elements
23399  tmp_sorted_ele_pt.push_front(unsorted_ele_pt[iproc][e]);
23400  // Add the face index to the list of sorted face index
23401  // elements
23402  tmp_sorted_face_index_ele.push_front(
23403  unsorted_face_index_ele[iproc][e]);
23404  if (!treat_as_inverted[iproc][e])
23405  {
23406  // Mark the element as inverted
23407  is_inverted[tmp_ele_pt] = true;
23408  }
23409  else
23410  {
23411  // Mark the element as not inverted
23412  is_inverted[tmp_ele_pt] = false;
23413  }
23414  // Set the flag to indicate a new element was added
23415  new_element_added = true;
23416  // Set the flag to indicate the element was added to
23417  // the left
23418  element_added_to_the_left = true;
23419  }
23420  // Check if the elements goes to the right
23421  else if (final_node_pt == first_node_pt
23422  && !connection_to_the_right)
23423  {
23424  // Update the final node and the just added node
23425  new_added_node_pt = final_node_pt = last_node_pt;
23426  // Add the most right node
23427  tmp_sorted_nodes_pt.push_back(last_node_pt);
23428  // Add the face element to the list of sorted face
23429  // elements
23430  tmp_sorted_face_ele_pt.push_back(tmp_ele_pt);
23431  // Add the bulk element to the list of sorted elements
23432  tmp_sorted_ele_pt.push_back(unsorted_ele_pt[iproc][e]);
23433  // Add the face index to the list of sorted face index
23434  // elements
23435  tmp_sorted_face_index_ele.push_back(
23436  unsorted_face_index_ele[iproc][e]);
23437  if (!treat_as_inverted[iproc][e])
23438  {
23439  // Mark the element as not inverted
23440  is_inverted[tmp_ele_pt] = false;
23441  }
23442  else
23443  {
23444  // Mark the element as inverted
23445  is_inverted[tmp_ele_pt] = true;
23446  }
23447  // Set the flag to indicate a new element was added
23448  new_element_added = true;
23449  // Set the flag to indicate the element was added to
23450  // the right
23451  element_added_to_the_right = true;
23452  }
23453  // Check if the elements goes to the right (but inverted)
23454  else if (final_node_pt == last_node_pt &&
23455  !connection_to_the_right)
23456  {
23457  // Update the final node and the just added node
23458  new_added_node_pt = final_node_pt = first_node_pt;
23459  // Add the most right node
23460  tmp_sorted_nodes_pt.push_back(first_node_pt);
23461  // Add the face element to the list of sorted face
23462  // elements
23463  tmp_sorted_face_ele_pt.push_back(tmp_ele_pt);
23464  // Add the bulk element to the list of sorted elements
23465  tmp_sorted_ele_pt.push_back(unsorted_ele_pt[iproc][e]);
23466  // Add the face index to the list of sorted face index
23467  // elements
23468  tmp_sorted_face_index_ele.push_back(
23469  unsorted_face_index_ele[iproc][e]);
23470  if (!treat_as_inverted[iproc][e])
23471  {
23472  // Mark the element as inverted
23473  is_inverted[tmp_ele_pt] = true;
23474  }
23475  else
23476  {
23477  // Mark the element as not inverted
23478  is_inverted[tmp_ele_pt] = false;
23479  }
23480  // Set the flag to indicate a new elements was added
23481  new_element_added = true;
23482  // Set the flag to indicate the element was added to
23483  // the right
23484  element_added_to_the_right = true;
23485  }
23486 
23487  // Do additional stuff if the element was added
23488  if (new_element_added)
23489  {
23490  // Mark the element as done
23491  done_ele[tmp_ele_pt] = true;
23492  // Increase the counter for sorted face elements
23493  nsorted_face_ele++;
23494 
23495  // Get the global degree of the node (notice the
23496  // local degree has been updated to global degree)
23497  const unsigned new_added_node_degree =
23498  global_node_degree[new_added_node_pt];
23499 
23500  // Based on which side the element was added, look for
23501  // connections on that side
23502 
23503  // Verify for connections to the left (we need to
23504  // check for the connection variable too, since
23505  // after a connection has been done we no longer
23506  // need to verify for this condition)
23507  if (element_added_to_the_left && !connection_to_the_left)
23508  {
23509  // Check for connection
23510  bound_id_connection_to_the_left =
23511  this->check_connections_of_polyline_nodes(
23512  element_in_processor_pt,
23513  root_edge_bound_id,
23514  overlapped_edge,
23515  node_on_bnd_not_overlapped_by_shd_bnd,
23516  tmp_sorted_nodes_pt,
23517  local_shd_bnd_id_to_sorted_list_node_pt,
23518  new_added_node_degree,
23519  new_added_node_pt,
23520  called_for_load_balance);
23521 
23522  // If there is a stop condition then set the
23523  // corresponding flag
23524  if (bound_id_connection_to_the_left != -1)
23525  {
23526  connection_to_the_left = true;
23527  } // if (bound_id_connection_to_the_left != -1)
23528 
23529  } // if (node_added_to_the_left &&
23530  // !connection_to_the_left)
23531 
23532  // Verify for connections to the right (we need to
23533  // check for the connection variable too, since
23534  // after a connection has been done we no longer
23535  // need to verify for this condition)
23536  if (element_added_to_the_right && !connection_to_the_right)
23537  {
23538  // Check for connection
23539  bound_id_connection_to_the_right =
23540  this->check_connections_of_polyline_nodes(
23541  element_in_processor_pt,
23542  root_edge_bound_id,
23543  overlapped_edge,
23544  node_on_bnd_not_overlapped_by_shd_bnd,
23545  tmp_sorted_nodes_pt,
23546  local_shd_bnd_id_to_sorted_list_node_pt,
23547  new_added_node_degree,
23548  new_added_node_pt,
23549  called_for_load_balance);
23550 
23551  // If there is a stop condition then set the
23552  // corresponding flag
23553  if (bound_id_connection_to_the_right != -1)
23554  {
23555  connection_to_the_right = true;
23556  } // if (bound_id_connection_to_the_right != -1)
23557 
23558  } // if (node_added_to_the_right &&
23559  // !connection_to_the_right)
23560 
23561  // If the current shared boundary has connections at
23562  // both ends then stop the adding of elements (and
23563  // nodes)
23564  if (connection_to_the_left && connection_to_the_right)
23565  {current_polyline_has_connections_at_both_ends = true;}
23566 
23567  // Break the for (looping over unsorted face
23568  // elements) and re-start looking for more elements
23569  // that fit to the left or right
23570  break;
23571 
23572  } // if (new_element_added)
23573 
23574  } // if (!done_ele[tmp_ele_pt])
23575 
23576  } // for (e < nunsorted_face_ele)
23577 
23578  } // while(new_element_added &&
23579  // (nsorted_face_ele < nunsorted_face_ele)
23580  // && !current_polyline_has_connections_at_both_ends)
23581 
23582  // ------------------------------------------------------------
23583  // Before assigning a local shared boundary id to the list of
23584  // nodes and boundary elements, check for any loop that the
23585  // shared boundary may be creating
23586 
23587  // The vector of the elements
23588  Vector<FiniteElement*> tmp_vector_sorted_ele_pt;
23589  // Store the list of elements on a vector of elements
23590  for (std::list<FiniteElement*>::iterator it =
23591  tmp_sorted_ele_pt.begin(); it != tmp_sorted_ele_pt.end(); it++)
23592  {
23593  tmp_vector_sorted_ele_pt.push_back((*it));
23594  }
23595 
23596  // The vector of the face elements
23597  Vector<FiniteElement*> tmp_vector_sorted_face_ele_pt;
23598  // Store the list of face elements on a vector of face
23599  // elements
23600  for (std::list<FiniteElement*>::iterator it =
23601  tmp_sorted_face_ele_pt.begin();
23602  it != tmp_sorted_face_ele_pt.end(); it++)
23603  {
23604  tmp_vector_sorted_face_ele_pt.push_back((*it));
23605  }
23606 
23607  // The vector of the face indexes
23608  Vector<int> tmp_vector_sorted_face_index_ele;
23609  // Store the list of elements on a vector of elements
23610  for (std::list<int>::iterator it =
23611  tmp_sorted_face_index_ele.begin();
23612  it != tmp_sorted_face_index_ele.end(); it++)
23613  {
23614  tmp_vector_sorted_face_index_ele.push_back((*it));
23615  }
23616 
23617  // Store the nodes for the new shared polylines without loops
23618  Vector<std::list<Node*> > final_sorted_nodes_pt;
23619  // Store the boundary elements of the shared polyline without
23620  // loops
23621  Vector<Vector<FiniteElement*> > final_boundary_element_pt;
23622  // Store the boundary face elements of the shared polyline
23623  // without loops
23624  Vector<Vector<FiniteElement*> > final_boundary_face_element_pt;
23625  // Face indexes of the boundary elements without loops
23626  Vector<Vector<int> > final_face_index_element;
23627  // Connection flags (to the left) of the shared boundaries
23628  // without loops
23629  Vector<int> final_bound_id_connection_to_the_left;
23630  // Connection flags (to the right) of the shared boundaries
23631  // without loops
23632  Vector<int> final_bound_id_connection_to_the_right;
23633 
23634  // Break any possible loop created by the shared polyline
23635  this->break_loops_on_shared_polyline_load_balance_helper(
23636  local_shd_bnd_id,
23637  tmp_sorted_nodes_pt,
23638  tmp_vector_sorted_ele_pt,
23639  tmp_vector_sorted_face_ele_pt, tmp_vector_sorted_face_index_ele,
23640  bound_id_connection_to_the_left, bound_id_connection_to_the_right,
23641  final_sorted_nodes_pt,
23642  final_boundary_element_pt,
23643  final_boundary_face_element_pt, final_face_index_element,
23644  final_bound_id_connection_to_the_left,
23645  final_bound_id_connection_to_the_right);
23646 
23647  // Get the number of final sorted nodes
23648  const unsigned n_final_sorted_nodes = final_sorted_nodes_pt.size();
23649 
23650  // Loop over the list of final sorted nodes
23651  for (unsigned i = 0; i < n_final_sorted_nodes; i++)
23652  {
23653  // Store the list of nodes that gave rise to the shared
23654  // boundary
23655  local_shd_bnd_id_to_sorted_list_node_pt[local_shd_bnd_id] =
23656  final_sorted_nodes_pt[i];
23657 
23658  // Store the local shared boundary id assigned to the
23659  // elements that will create the shared boundary
23660  proc_local_shared_boundary_id[iproc].push_back(local_shd_bnd_id);
23661 
23662  // Increase the shared boundary id (note that this is only
23663  // used to keep track of the list of nodes that create the
23664  // shared boundaries in the current processor)
23665  local_shd_bnd_id++;
23666 
23667  // Include the vector of elements to the sorted vector
23668  sorted_ele_pt[iproc].push_back(final_boundary_element_pt[i]);
23669 
23670  // Include the vector of face elements to the sorted vector
23671  sorted_face_ele_pt[iproc].
23672  push_back(final_boundary_face_element_pt[i]);
23673 
23674  // Include the vector of elements to the sorted vector
23675  sorted_face_index_ele[iproc].push_back(final_face_index_element[i]);
23676 
23677  // Include the possible associated boundary id to the vector
23678  edge_boundary_id[iproc].push_back(root_edge_bound_id);
23679 
23680  // Include the connection information associated with the
23681  // current set of face elements (that will give rise to a
23682  // shared polyline
23683  // The temporal storage for the boundary connections ids
23684  Vector<int> bnd_connections_ids(2);
23685  bnd_connections_ids[0] = final_bound_id_connection_to_the_left[i];
23686  bnd_connections_ids[1] = final_bound_id_connection_to_the_right[i];
23687  sorted_connection_info[iproc].push_back(bnd_connections_ids);
23688 
23689  } // for (i < n_final_sorted_nodes)
23690 
23691  } // while (nsorted_face_ele < nunsorted_face_ele)
23692 
23693  } // if (iproc != my_rank)
23694 
23695  } // for (iproc < nproc)
23696 
23697  // The time to sort shared boundaries face elements to create a
23698  // continuous representation of the boundary
23699  if (Print_timings_level_load_balance>2)
23700  {
23701  oomph_info << "CPU for joining shared boundary face elements (load balance) [9.5]: "
23702  <<TimingHelpers::timer()-tt_start_join_shd_bnd_face_ele
23703  << std::endl;
23704  }
23705 
23706  // ==================================================================
23707  // END: SORT THE SHARED BOUNDARY FACE ELEMENTS, ADD FACE ELEMENTS TO
23708  // THE LEFT OR RIGHT OF THE ROOT FACE ELEMENT. STOP ADDING WHEN THE
23709  // MOST LEFT OR MOST RIGHT ELEMENT (NODE) IS ALREADY PART OF ANOTHER
23710  // BOUNDARY (THIS MEANS THAT THE SHARED BOUNDARY THAT IS BEING
23711  // CREATED HAS A CONNECTION). ALSO REMEMBER TO CHECK FOR THE CASE
23712  // WHEN THE MOST LEFT OR MOST RIGHT NODE IS A BOUNDARY NODE OF A
23713  // BOUNDARY THAT NO LONGER EXIST IN THE DOMAIN. AT THE END OF THIS
23714  // SECTION WE WILL HAVE THE NUMBER OF SHARED BOUNDARIES OF THIS
23715  // PROCESSOR WITH OTHERS BUT NOT THE GLOBAL SHARED BOUNDARY ID
23716  // ==================================================================
23717 
23718  // ==================================================================
23719  // BEGIN: COMPUTE THE GLOBAL SHARED BOUNDARIES IDS. GATHER THE
23720  // NUMBER OF SHARED BOUNDARIES OF EACH PROCESSOR, THEN A ROOT
23721  // PROCESSOR IS IN CHARGE OF VERIFYING THAT THE SAME NUMBER OF
23722  // SHARED BOUNDARIES HAVE BEEN CREATED BY A PAIR OF PROCESSORS. THE
23723  // ROOT PROCESSOR COMPUTES THE INITIAL GLOBAL SHARED BOUNDARY ID
23724  // BETWEEN EACH PAIR OR PROCESSORS AND SENDS THESE INFO. TO ALL
23725  // PROCESSORS. THE GLOBAL INITIAL AND FINAL SHARED BOUNDARY ID ARE
23726  // ALSO COMPUTED
23727  // ==================================================================
23728 
23729  // Get the time to compute new shared boundaries ids
23730  double tt_start_get_new_shared_boundaries_ids=0.0;
23731  if (Print_timings_level_load_balance>2)
23732  {
23733  tt_start_get_new_shared_boundaries_ids=TimingHelpers::timer();
23734  }
23735 
23736  // Get the number of shared boundaries with in each processor
23737  Vector<unsigned> nshared_boundaries_with_processor(nproc);
23738  // Loop over the processors
23739  for (unsigned iproc = 0; iproc < nproc; iproc++)
23740  {
23741  // No shared boundaries with myself
23742  if (iproc != my_rank)
23743  {
23744  // Store the number of shared boundaries of the current
23745  // processor (my_rank) with the iproc processor
23746  nshared_boundaries_with_processor[iproc] =
23747  sorted_face_ele_pt[iproc].size();
23748 
23749  } // if (iproc != my_rank)
23750 
23751  } // for (iproc < nproc)
23752 
23753  // Each processor sends the number of shared boundaries that it has
23754  // with in each other processor to the "root_processor" which will
23755  // be in charge of checking and computing the global shared
23756  // boundaries ids
23757  const unsigned root_processor = 0;
23758 
23759  // Get the communicator of the mesh
23760  OomphCommunicator* comm_pt = this->communicator_pt();
23761 
23762  // Container where to store the info. received from other processor
23763  // in root. It receives from all processors the number of shared
23764  // boundaries that each one has with any other processor
23765  Vector<unsigned> flat_unsigned_root_received_data(nproc*nproc);
23766 
23767  // Gather the info. in the "root_processor"
23768  MPI_Gather(&nshared_boundaries_with_processor[0], // Info. sent from
23769  // each processor
23770  nproc, // Total number of data to send from each
23771  // processor
23772  MPI_UNSIGNED,
23773  &flat_unsigned_root_received_data[0], // Container where
23774  // to receive the
23775  // info. from all
23776  // the processors
23777  nproc, // Number of data to receive from each processor
23778  MPI_UNSIGNED,
23779  root_processor, // The processor that receives all the
23780  // info.
23781  comm_pt->mpi_comm());
23782 
23783  // Container where root store the info. that will be sent back to
23784  // all processor, because root performs a Broadcast operation then
23785  // the info. is received in the same container
23786  Vector<unsigned> flat_unsigned_root_send_receive_data;
23787 
23788  // Compute the new initial and final shared boundary id (they are
23789  // based on the global number of shared boundaries)
23790  unsigned new_initial_shared_boundary_id = 0;
23791  unsigned new_final_shared_boundary_id = 0;
23792 
23793  // Compute the boundaries ids for the shared boundaries
23794  if (my_rank == root_processor)
23795  {
23796  // Change the representation of the data received from all
23797  // processors to a matrix representation for ease access
23798  Vector<Vector<unsigned> > root_nshared_bound_proc_with_proc(nproc);
23799  // Loop over the processors and get the number of shared
23800  // boundaries of processor iproc with jproc
23801  for (unsigned iproc = 0; iproc < nproc; iproc++)
23802  {
23803  // Resize the vector to store the data
23804  root_nshared_bound_proc_with_proc[iproc].resize(nproc);
23805  // Loop over the processors and get the number of shared
23806  // boundaries of processor iproc with jproc
23807  for (unsigned jproc = 0; jproc < nproc; jproc++)
23808  {
23809  root_nshared_bound_proc_with_proc[iproc][jproc] =
23810  flat_unsigned_root_received_data[(iproc * nproc) + jproc];
23811 
23812  } // for (jproc < nproc)
23813 
23814  } // for (iproc < nproc)
23815 
23816 #ifdef PARANOID
23817  // Check that the same number of boundaries are shared by two
23818  // specific processors
23819  for (unsigned iproc = 0; iproc < nproc; iproc++)
23820  {
23821  for (unsigned jproc = 0; jproc < iproc; jproc++)
23822  {
23823  if (root_nshared_bound_proc_with_proc[iproc][jproc] !=
23824  root_nshared_bound_proc_with_proc[jproc][iproc])
23825  {
23826  std::ostringstream error_stream;
23827  error_stream
23828  << "ROOT PROCESSOR ERROR\n\n"
23829  << "The number of shared boundaries between processor ("
23830  << iproc << ") and (" << jproc << ") is not the same:\n"
23831  << "Shared boundaries of processor (" << iproc
23832  << ") with processor (" << jproc << "): ("
23833  << root_nshared_bound_proc_with_proc[iproc][jproc] << ")\n"
23834  << "Shared boundaries of processor (" << jproc
23835  << ") with processor (" << iproc << "): ("
23836  << root_nshared_bound_proc_with_proc[jproc][iproc] << ")\n\n";
23837  throw OomphLibError(error_stream.str(),
23838  OOMPH_CURRENT_FUNCTION,
23839  OOMPH_EXCEPTION_LOCATION);
23840 
23841  } // The number of shared boundaries between processors
23842  // "iproc" and "jproc" is not the same
23843 
23844  } // for (jproc < iproc)
23845 
23846  } // for (iproc < nproc)
23847 #endif
23848 
23849  // The enumeration of the shared boundaries starts from the lowest
23850  // processor number to the highest processor number
23851 
23852  // Two processors share the same boundaries ids, the lowest
23853  // processor number is the one in charge of computing the shared
23854  // boundaries ids
23855  Vector<Vector<unsigned> > start_shared_bound_id_proc_with_proc(nproc);
23856  // Resize the vector, we can not do it when storing the
23857  // info. because of the strategy to save the info.
23858  for (unsigned iproc = 0; iproc < nproc; iproc++)
23859  {start_shared_bound_id_proc_with_proc[iproc].resize(nproc);}
23860 
23861  // The shared boundaries ids start from the current number of
23862  // original boundaries
23863  unsigned shared_bound_id = this->nboundary();
23864 
23865  // Set the new initial shared boundary id
23866  new_initial_shared_boundary_id = shared_bound_id;
23867 
23868  // Assign the global shared boundary id for the shared boundaries
23869  for (unsigned iproc = 0; iproc < nproc; iproc++)
23870  {
23871  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
23872  {
23873  // Are there shared boundaries between the pair of processors
23874  if (root_nshared_bound_proc_with_proc[iproc][jproc] > 0)
23875  {
23876  // Set the start boundary id of processor "iproc" with
23877  // processor "jproc" and viceversa
23878  start_shared_bound_id_proc_with_proc[iproc][jproc] = shared_bound_id;
23879  start_shared_bound_id_proc_with_proc[jproc][iproc] = shared_bound_id;
23880  // Increase the shared boundary id counter with as many
23881  // shared boundaries there are between the iproc and jproc
23882  // processor
23883  shared_bound_id+= root_nshared_bound_proc_with_proc[iproc][jproc];
23884  } // if (root_nshared_bound_proc_with_proc[iproc][jproc] > 0)
23885 
23886  } // for (jproc < iproc)
23887 
23888  } // for (iproc < nproc)
23889 
23890  // Set the new final shared boundary id
23891  new_final_shared_boundary_id = shared_bound_id;
23892 
23893  // Prepare the info. to send back to each processor
23894  Vector<unsigned> send_start_shared_bound_id_proc_with_proc(nproc*nproc);
23895 
23896  // Copy the info. to the storage to send the info. back to other
23897  // processors
23898  for (unsigned iproc = 0; iproc < nproc; iproc++)
23899  {
23900  for (unsigned jproc = 0; jproc < nproc; jproc++)
23901  {
23902  // Get the initial shared boundary id between each pair of
23903  // processors (iproc, jproc)
23904  const unsigned initial_shd_bnd_id =
23905  start_shared_bound_id_proc_with_proc[iproc][jproc];
23906  flat_unsigned_root_send_receive_data.push_back(initial_shd_bnd_id);
23907 
23908  // .. then copy the number of shared boundaries that there are
23909  // between processor iproc and jproc
23910  const unsigned nshared_bnd_iproc_jproc =
23911  root_nshared_bound_proc_with_proc[iproc][jproc];
23912  flat_unsigned_root_send_receive_data.push_back(nshared_bnd_iproc_jproc);
23913 
23914  } // for (jproc < nproc)
23915 
23916  } // for (iproc < nproc)
23917 
23918  // .. at the end of the data to send include the global initial
23919  // shared boundary id
23920  flat_unsigned_root_send_receive_data.
23921  push_back(new_initial_shared_boundary_id);
23922 
23923  // ... and the global final shared boundary id
23924  flat_unsigned_root_send_receive_data.
23925  push_back(new_final_shared_boundary_id);
23926 
23927  } // if (my_rank == root_processor)
23928 
23929  // Send the initial shared boundaries ids and the number of shared
23930  // boundaries between all procesors to all processors. All
23931  // processors need to know this info.
23932 
23933  // The number of data that will be sent by root to other processors
23934  // and the number of data that other processors receive from root,
23935  // it is the same because it is performed via a Broadcast
23936  unsigned root_ndata_sent_to_all_proc =
23937  flat_unsigned_root_send_receive_data.size();
23938 
23939  MPI_Bcast(&root_ndata_sent_to_all_proc, // Data to send
23940  1, MPI_UNSIGNED, root_processor,
23941  comm_pt->mpi_comm());
23942 
23943  // Resize the container if this is a processor that receives data
23944  if (my_rank != root_processor)
23945  {
23946  flat_unsigned_root_send_receive_data.resize(root_ndata_sent_to_all_proc);
23947  }
23948 
23949  // Send back the start boundaries ids for the shared boundaries
23950  // Scatter the info. from the "root_processor"
23951  MPI_Bcast(&flat_unsigned_root_send_receive_data[0], // Info. sent to
23952  // each
23953  // processor
23954  root_ndata_sent_to_all_proc, // Total number of data to
23955  // send to each processor
23956  MPI_UNSIGNED,
23957  root_processor, // The processor that sends all the info.
23958  comm_pt->mpi_comm());
23959 
23960  // The container to store the initial shared boundaries ids between
23961  // each pair of processors
23962  Vector<Vector<unsigned> > initial_shared_bound_id_proc_with_proc(nproc);
23963 
23964  // All processors need to know how many shared boundaries there are
23965  // between each pair of processors
23966 
23967  // The number of shared boundaries between each pair of processors
23968  Vector<Vector<unsigned> > nshared_bound_proc_with_proc(nproc);
23969 
23970  unsigned iflat_counter = 0;
23971  // Fill the containers with the received info. from root processor
23972  for (unsigned iproc = 0; iproc < nproc; iproc++)
23973  {
23974  // Resize the containers
23975  initial_shared_bound_id_proc_with_proc[iproc].resize(nproc);
23976  nshared_bound_proc_with_proc[iproc].resize(nproc);
23977 
23978  // Loop over the processors
23979  for (unsigned jproc = 0; jproc < nproc; jproc++)
23980  {
23981  // Get the initial shared boundary id between each pair of
23982  // processors (iproc, jproc)
23983  initial_shared_bound_id_proc_with_proc[iproc][jproc] =
23984  flat_unsigned_root_send_receive_data[iflat_counter++];
23985 
23986  // .. and copy the number of shared boundaries that there are
23987  // between processor iproc and jproc
23988  nshared_bound_proc_with_proc[iproc][jproc] =
23989  flat_unsigned_root_send_receive_data[iflat_counter++];
23990 
23991  } // for (jproc < nproc)
23992 
23993  } // for (iproc < nproc)
23994 
23995  // Read the new initial shared boundary id
23996  new_initial_shared_boundary_id =
23997  flat_unsigned_root_send_receive_data[root_ndata_sent_to_all_proc-2];
23998 
23999  // Read the new final shared boundary id
24000  new_final_shared_boundary_id =
24001  flat_unsigned_root_send_receive_data[root_ndata_sent_to_all_proc-1];
24002 
24003  // The time to compute new shared boundaries ids
24004  if (Print_timings_level_load_balance>2)
24005  {
24006  oomph_info << "CPU for computing new shared boundaries ids (load balance) [9.6]: "
24007  <<TimingHelpers::timer()-tt_start_get_new_shared_boundaries_ids
24008  << std::endl;
24009  }
24010 
24011  // ==================================================================
24012  // END: COMPUTE THE GLOBAL SHARED BOUNDARIES IDS. GATHER THE NUMBER
24013  // OF SHARED BOUNDARIES OF EACH PROCESSOR, THEN A ROOT PROCESSOR IS
24014  // IN CHARGE OF VERIFYING THAT THE SAME NUMBER OF SHARED BOUNDARIES
24015  // HAVE BEEN CREATED BY A PAIR OF PROCESSORS. THE ROOT PROCESSOR
24016  // COMPUTES THE INITIAL GLOBAL SHARED BOUNDARY ID BETWEEN EACH PAIR
24017  // OR PROCESSORS AND SENDS THESE INFO. TO ALL PROCESSORS. THE GLOBAL
24018  // INITIAL AND FINAL SHARED BOUNDARY ID ARE ALSO COMPUTED
24019  // ==================================================================
24020 
24021  // ==================================================================
24022  // BEGIN: CREATE THE NEW SHARED BOUNDARIES. DELETE THE OLD SHARED
24023  // BOUNDARIES INFORMATION. FILL THE DATA STRUCTURES WITH THE NEW
24024  // SHARED BOUNDARIES INFO.
24025  // ==================================================================
24026 
24027  // Get the time to create new shared boundaries representations
24028  double tt_start_create_new_shared_boundaries_polylines=0.0;
24029  if (Print_timings_level_load_balance>2)
24030  {
24031  tt_start_create_new_shared_boundaries_polylines=TimingHelpers::timer();
24032  }
24033 
24034  // Create the shared boundaries and establish all the related info.
24035  // - Create Polylines
24036  // - Store shared boundary elements
24037  // - Fill data structures to know which shared boundaries belong to
24038  // which processor
24039 
24040  // Resize the shared polylines container
24041  this->flush_shared_boundary_polyline_pt();
24042  this->Shared_boundary_polyline_pt.resize(nproc);
24043 
24044  // Resize for the boundaries ids shared with all processors
24045  this->Shared_boundaries_ids.clear();
24046  this->Shared_boundaries_ids.resize(nproc);
24047  for (unsigned iproc = 0; iproc < nproc; iproc++)
24048  {
24049  this->Shared_boundaries_ids[iproc].clear();
24050  this->Shared_boundaries_ids[iproc].resize(nproc);
24051  } // for (iproc < nproc)
24052 
24053  // Clear data
24054  this->Shared_boundary_from_processors.clear();
24055  this->Shared_boundary_overlaps_internal_boundary.clear();
24056  this->Boundary_was_splitted.clear();
24057  this->Boundary_subpolylines.clear();
24058  this->Boundary_marked_as_shared_boundary.clear();
24059 
24060  // Flush data
24061  this->flush_shared_boundary_element();
24062  this->flush_face_index_at_shared_boundary();
24063  this->flush_shared_boundary_node();
24064  this->flush_sorted_shared_boundary_node();
24065 
24066  // Store the old local inital shared boundary id (used to map from
24067  // local shared boundary id to global shared boundary id)
24068  const unsigned old_local_shd_bnd_id = this->Initial_shared_boundary_id;
24069 
24070  // Update the initial and final shared boundary id
24071  this->Initial_shared_boundary_id = new_initial_shared_boundary_id;
24072  this->Final_shared_boundary_id = new_final_shared_boundary_id;
24073 
24074  // Storage for the new created polylines between the current
24075  // processor (my_rank) and the other processors, unsorted polylines
24076  Vector<TriangleMeshPolyLine *> unsorted_polylines_pt;
24077 
24078  // Map to get the global shared boundary id from the local shared
24079  // boundary id. Note that this is only used to get the global shared
24080  // boundary id when the shared boundary that is being created has
24081  // connections
24082  std::map<unsigned, unsigned> local_to_global_shd_bnd_id;
24083 
24084  // Each processor knows the boundaries ids for each of the shared
24085  // boundaries it has, establish that info. in the proper containers
24086  // Additionally, store the shared boundaries of ALL processors with
24087  // ALL processors, but only create the shared boundaries (and their
24088  // respective polylines) of the current processor (my_rank)
24089  for (unsigned iproc = 0; iproc < nproc; iproc++)
24090  {
24091  // Avoid creating double shared boundaries, the shared boundaries
24092  // created between processor "iproc" and processor "jproc" are the
24093  // same than those created between processor "jproc" and processor
24094  // "iproc"
24095  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
24096  {
24097  // If we are working with the current processor (my_rank) then
24098  // create the shared boundaries, if that is not the case then
24099  // only fill the info. on the proper containers
24100  if (iproc == my_rank || jproc == my_rank)
24101  {
24102  // Check the condition that made it get here
24103  unsigned ref_proc = 0;
24104  if (iproc == my_rank)
24105  {ref_proc = jproc;}
24106  else if (jproc == my_rank)
24107  {ref_proc = iproc;}
24108 
24109  // Get the number of shared boundaries between processor iproc
24110  // and processor jproc
24111  const unsigned nshared_bound_iproc_jproc =
24112  nshared_bound_proc_with_proc[iproc][jproc];
24113 
24114  // Loop over the number of shared boundaries
24115  for (unsigned counter = 0;
24116  counter < nshared_bound_iproc_jproc;
24117  counter++)
24118  {
24119  // Compute the shared boundary id for the shared boundary
24120  const unsigned shd_bnd_id =
24121  initial_shared_bound_id_proc_with_proc[iproc][jproc] + counter;
24122  // Set up the shared boundaries between "iproc" (my_rank)
24123  // and "jproc"
24124  this->Shared_boundaries_ids[iproc][jproc].push_back(shd_bnd_id);
24125  this->Shared_boundaries_ids[jproc][iproc].push_back(shd_bnd_id);
24126 
24127  // Specify the processors involved for the creation of the
24128  // shared boundary
24129  Vector<unsigned> processors(2);
24130  processors[0] = iproc;
24131  processors[1] = jproc;
24132  this->Shared_boundary_from_processors[shd_bnd_id] = processors;
24133 
24134  // Get the possible root edge id associated to the shared
24135  // boundary (useful when the shared boundary overlaps an
24136  // original boundary)
24137  int root_edge_bound_id = edge_boundary_id[ref_proc][counter];
24138  // Check if the shared boundary is overlapping (or is part)
24139  // of an internal boundary
24140  if (root_edge_bound_id != -1)
24141  {
24142  // If the shared boundary is part of an internal boundary then
24143  // mark the shared boundary
24144  this->Shared_boundary_overlaps_internal_boundary[shd_bnd_id] =
24145  static_cast<unsigned>(root_edge_bound_id);
24146  } // if (root_edge_bound_id != -1)
24147 
24148  // Storing for the nodes of the polyline (these are different
24149  // from the nodes on the face elements -- it is actually a
24150  // sub-set -- since the polyline is created from the first and
24151  // last nodes on the face elements)
24152  Vector<Node*> node_pt_to_create_shared_polyline;
24153 
24154  // Add the first node for the very first face element. In
24155  // the loop we will only add the last node of the face
24156  // element
24157  FiniteElement* first_face_ele_pt =
24158  sorted_face_ele_pt[ref_proc][counter][0];
24159 
24160  // Get the number of nodes on the first face element
24161  const unsigned first_face_ele_nnodes = first_face_ele_pt->nnode();
24162  if (!is_inverted[first_face_ele_pt])
24163  {
24164  // Get the first node
24165  Node* first_node_pt = first_face_ele_pt->node_pt(0);
24166  // Add the node to create the polyline
24167  node_pt_to_create_shared_polyline.push_back(first_node_pt);
24168  // Add the first node to the shared boundary
24169  this->add_shared_boundary_node(shd_bnd_id, first_node_pt);
24170  }
24171  else
24172  {
24173  // Get the first node in the inverted face element
24174  Node* first_node_pt =
24175  first_face_ele_pt->node_pt(first_face_ele_nnodes - 1);
24176  // Add the node to create the polyline
24177  node_pt_to_create_shared_polyline.push_back(first_node_pt);
24178  // Add the first node to the shared boundary
24179  this->add_shared_boundary_node(shd_bnd_id, first_node_pt);
24180  }
24181 
24182  // ... and extract only the last nodes of the face elements
24183  // in the next loop and add them in the vector of nodes to
24184  // create polylines (node_pt_to_create_shared_polyline)
24185 
24186  // Get the number of elements
24187  const unsigned nshared_boundary_elements =
24188  sorted_face_ele_pt[ref_proc][counter].size();
24189 
24190  // Store the shared boundary elements, nodes and get the
24191  // sorted nodes to create the polyline
24192  for (unsigned ie = 0 ; ie < nshared_boundary_elements; ie++)
24193  {
24194  // Get the bulk element version of the face element
24195  FiniteElement* bulk_ele_pt = sorted_ele_pt[ref_proc][counter][ie];
24196 
24197  // Add the shared boundary element and associate it to the
24198  // "shd_bnd_id"
24199  this->add_shared_boundary_element(shd_bnd_id,
24200  bulk_ele_pt);
24201 
24202  // Get the face index from which the face element was
24203  // created from the bulk element
24204  const int face_index =
24205  sorted_face_index_ele[ref_proc][counter][ie];
24206 
24207  // Add the face index to the face indexes of the shared
24208  // boundary
24209  this->add_face_index_at_shared_boundary(shd_bnd_id,
24210  face_index);
24211 
24212  // Get the face element to obtain the last node
24213  FiniteElement* face_ele_pt =
24214  sorted_face_ele_pt[ref_proc][counter][ie];
24215 
24216  // Get the number of nodes
24217  const unsigned nnodes = face_ele_pt->nnode();
24218  if (!is_inverted[face_ele_pt])
24219  {
24220  // We have already added the first node, then start from
24221  // the second one
24222  for (unsigned n = 1; n < nnodes; n++)
24223  {
24224  // Get the node to be added
24225  Node* node_pt = face_ele_pt->node_pt(n);
24226  // Add the node and associate it to the shared boundary
24227  this->add_shared_boundary_node(shd_bnd_id, node_pt);
24228  } // for (n < nnodes)
24229 
24230  // Add the last node of the face element to the vector of
24231  // nodes to create the polyline
24232  // Get the last node
24233  Node* last_node_pt = face_ele_pt->node_pt(nnodes - 1);
24234  node_pt_to_create_shared_polyline.push_back(last_node_pt);
24235  } // if (!is_inverted[face_ele_pt])
24236  else
24237  {
24238  // We have already added the first node, then start from
24239  // the second one (in reverse order)
24240  for (int n = nnodes-2; n >= 0; n--)
24241  {
24242  // Get the node to be added
24243  Node* node_pt = face_ele_pt->node_pt(n);
24244  // Add the node and associate it to the shared boundary
24245  this->add_shared_boundary_node(shd_bnd_id, node_pt);
24246  } // for (n < nnodes)
24247 
24248  // Add the last node of the face element to the vector of
24249  // nodes to create the polyline
24250  // Get the last node
24251  Node* last_node_pt = face_ele_pt->node_pt(0);
24252  node_pt_to_create_shared_polyline.push_back(last_node_pt);
24253 
24254  } // else if (!is_inverted[face_ele_pt])
24255 
24256  } // for (ie < nshared_boundary_elements)
24257 
24258  // The number of nodes for the shared boundary polyline
24259  const unsigned nnodes_to_create_shared_boundary =
24260  node_pt_to_create_shared_polyline.size();
24261 
24262  // Get the vertices that create the shared boundary polyline
24263  Vector<Vector<double> > vertices(nnodes_to_create_shared_boundary);
24264  for (unsigned n = 0; n < nnodes_to_create_shared_boundary; n++)
24265  {
24266  vertices[n].resize(2);
24267  // Get the node
24268  Node* tmp_node_pt = node_pt_to_create_shared_polyline[n];
24269  // Get the vertices
24270  vertices[n][0] = tmp_node_pt->x(0);
24271  vertices[n][1] = tmp_node_pt->x(1);
24272  } // for (n < nnodes_to_create_shared_boundary)
24273 
24274  // Create the polyline
24275  TriangleMeshPolyLine *polyline_pt =
24276  new TriangleMeshPolyLine(vertices, shd_bnd_id);
24277 
24278  // Updates bnd_id<--->curve section map
24279  this->Boundary_curve_section_pt[shd_bnd_id] = polyline_pt;
24280 
24281  // Add the new created polyline to the list of unsorted
24282  // polylines
24283  unsorted_polylines_pt.push_back(polyline_pt);
24284 
24285  // Mark the polyline for deletion (when calling destructor)
24286  this->Free_curve_section_pt.insert(polyline_pt);
24287 
24288  // Now assign the connection information
24289  // ---------------------------------------------------------
24290  // Get the local shared boundary id associated to the
24291  // elements that gave rise to this shared boundary
24292  const unsigned local_shd_bnd_id =
24293  proc_local_shared_boundary_id[ref_proc][counter];
24294 
24295  // Associate the local shared boundary to the global shared
24296  // boundary
24297  local_to_global_shd_bnd_id[local_shd_bnd_id] = shd_bnd_id;
24298 
24299  // Get the correct shared boundaries ids, from the local
24300  // shared boundaries ids established at the identification
24301  // of the conections
24302 
24303  // Get the local bnd id for the connection to the left
24304  int tmp_bnd_id_connection_to_the_left =
24305  sorted_connection_info[ref_proc][counter][0];
24306  // Get the local bnd id for the connection to the right
24307  int tmp_bnd_id_connection_to_the_right =
24308  sorted_connection_info[ref_proc][counter][1];
24309 
24310  // The global shared boundaries ids for connections to the
24311  // left or right
24312  int bnd_id_connection_to_the_left = -1;
24313  int bnd_id_connection_to_the_right = -1;
24314 
24315  // To the left
24316  // --------------
24317 
24318  // If the connection is with the same shared boundary then
24319  // set the current boundary id
24320  if (tmp_bnd_id_connection_to_the_left == -2)
24321  {
24322  // Set the current shared boundary id
24323  bnd_id_connection_to_the_left = shd_bnd_id;
24324  } // if (tmp_bnd_id_connection_to_the_left == -2)
24325 
24326  // Check if the connection was a stop adding nodes condition
24327  if (tmp_bnd_id_connection_to_the_left == -3)
24328  {
24329  // Set as no connected
24330  bnd_id_connection_to_the_left = -1;
24331  } // if (tmp_bnd_id_connection_to_the_left == -3)
24332 
24333  // There is a connection with another boundary, check if it
24334  // is a shared boundary or an original boundary
24335  if (tmp_bnd_id_connection_to_the_left >=
24336  static_cast<int>(old_local_shd_bnd_id))
24337  {
24338  // The connection is with a shared boundary, get the
24339  // global shared boundary id and set the connection
24340 #ifdef PARANOID
24341  std::map<unsigned, unsigned>::iterator it =
24342  local_to_global_shd_bnd_id.find(
24343  static_cast<unsigned>(tmp_bnd_id_connection_to_the_left));
24344  // If the global shared boundary id was not found we
24345  // are in trouble
24346  if (it==local_to_global_shd_bnd_id.end())
24347  {
24348  std::stringstream error_message;
24349  error_message
24350  << "The global shared boundary id was not found for\n"
24351  << "the local shared boundary shared with processor ("
24352  << ref_proc <<").\n"
24353  << "This processor: (" << my_rank << ")\n"
24354  << "Boundary shared with processor: (" << ref_proc << ")\n"
24355  << "Local shared boundary: ("
24356  << tmp_bnd_id_connection_to_the_left << ")\n";
24357  throw OomphLibError(error_message.str(),
24358  OOMPH_CURRENT_FUNCTION,
24359  OOMPH_EXCEPTION_LOCATION);
24360  } // if (it==local_to_global_shd_bnd_id.end())
24361 #endif
24362 
24363  // Get the global shared boundary id
24364  bnd_id_connection_to_the_left =
24365  local_to_global_shd_bnd_id[
24366  static_cast<unsigned>(tmp_bnd_id_connection_to_the_left)];
24367 
24368  }
24369  else
24370  {
24371  // The connection is with an original boundary, copy
24372  // the boundary id
24373  bnd_id_connection_to_the_left =
24374  tmp_bnd_id_connection_to_the_left;
24375 
24376  } // else (connection with a shared boundary)
24377 
24378  // To the right
24379  // --------------
24380 
24381  // If the connection is with the same shared boundary then
24382  // set the current boundary id
24383  if (tmp_bnd_id_connection_to_the_right == -2)
24384  {
24385  // Set the current shared boundary id
24386  bnd_id_connection_to_the_right = shd_bnd_id;
24387  } // if (tmp_bnd_id_connection_to_the_right == -2)
24388 
24389  // Check if the connection was a stop adding nodes condition
24390  if (tmp_bnd_id_connection_to_the_right == -3)
24391  {
24392  // Set as no connected
24393  bnd_id_connection_to_the_right = -1;
24394  } // if (tmp_bnd_id_connection_to_the_right == -3)
24395 
24396  // There is a connection with another boundary, check if it
24397  // is a shared boundary or an original boundary
24398  if (tmp_bnd_id_connection_to_the_right >=
24399  static_cast<int>(old_local_shd_bnd_id))
24400  {
24401  // The connection is with a shared boundary, get the
24402  // global shared boundary id and set the connection
24403 #ifdef PARANOID
24404  std::map<unsigned, unsigned>::iterator it =
24405  local_to_global_shd_bnd_id.find(
24406  static_cast<unsigned>(tmp_bnd_id_connection_to_the_right));
24407  // If the global shared boundary id was not found we
24408  // are in trouble
24409  if (it==local_to_global_shd_bnd_id.end())
24410  {
24411  std::stringstream error_message;
24412  error_message
24413  << "The global shared boundary id was not found for\n"
24414  << "the local shared boundary shared with processor ("
24415  << ref_proc <<").\n"
24416  << "This processor: (" << my_rank << ")\n"
24417  << "Boundary shared with processor: (" << ref_proc << ")\n"
24418  << "Local shared boundary: ("
24419  << tmp_bnd_id_connection_to_the_right << ")\n";
24420  throw OomphLibError(error_message.str(),
24421  OOMPH_CURRENT_FUNCTION,
24422  OOMPH_EXCEPTION_LOCATION);
24423  } // if (it==local_to_global_shd_bnd_id.end())
24424 #endif
24425  // Get the global shared boundary id
24426  bnd_id_connection_to_the_right =
24427  local_to_global_shd_bnd_id[
24428  static_cast<unsigned>(tmp_bnd_id_connection_to_the_right)];
24429 
24430  }
24431  else
24432  {
24433  // The connection is with an original boundary, copy the
24434  // boundary id
24435  bnd_id_connection_to_the_right =
24436  tmp_bnd_id_connection_to_the_right;
24437 
24438  } // else (connection with a shared boundary)
24439 
24440  // --------------------------------
24441  // Set the connection to the left
24442  if (bnd_id_connection_to_the_left != -1)
24443  {
24444  // Get the unsigned version of the boundary id to the left
24445  const unsigned ubnd_id_connection_to_the_left =
24446  static_cast<unsigned>(bnd_id_connection_to_the_left);
24447  // Set the initial vertex as connected
24448  polyline_pt->set_initial_vertex_connected();
24449  // Set the initial vertex connected boundary id
24450  polyline_pt->initial_vertex_connected_bnd_id() =
24451  ubnd_id_connection_to_the_left;
24452  // Set the chunk number to zero
24453  polyline_pt->initial_vertex_connected_n_chunk() = 0;
24454 
24455  } // if (bnd_id_connection_to_the_left != -1)
24456 
24457  // ---------------------------------
24458  // Set the connection to the right
24459  if (bnd_id_connection_to_the_right != -1)
24460  {
24461  // Get the unsigned version of the boundary id to the
24462  // right
24463  const unsigned ubnd_id_connection_to_the_right =
24464  static_cast<unsigned>(bnd_id_connection_to_the_right);
24465  // Set the final vertex as connected
24466  polyline_pt->set_final_vertex_connected();
24467  // Set the final vertex connected boundary id
24468  polyline_pt->final_vertex_connected_bnd_id() =
24469  ubnd_id_connection_to_the_right;
24470  // Set the chunk number to zero
24471  polyline_pt->final_vertex_connected_n_chunk() = 0;
24472 
24473  } // if (bnd_id_connection_to_the_right != -1)
24474 
24475  } // for (counter < nshared_bound_iproc_jproc)
24476 
24477  } // if (iproc == my_rank || jproc == my_rank)
24478  else
24479  {
24480  // We are not working with the current processor, then we only
24481  // need to fill the containers
24482 
24483  // Get the number of shared boundaries between processor iproc
24484  // and processor jproc
24485  const unsigned nshared_bound_iproc_jproc =
24486  nshared_bound_proc_with_proc[iproc][jproc];
24487  // Loop over the number of shared boundaries
24488  for (unsigned counter = 0;
24489  counter < nshared_bound_iproc_jproc;
24490  counter++)
24491  {
24492  // Compute the shared boundary id for the shared boundary
24493  const unsigned shd_bnd_id =
24494  initial_shared_bound_id_proc_with_proc[iproc][jproc] + counter;
24495 
24496  // Set up the shared boundaries between "iproc" and "jproc"
24497  this->Shared_boundaries_ids[iproc][jproc].push_back(shd_bnd_id);
24498  this->Shared_boundaries_ids[jproc][iproc].push_back(shd_bnd_id);
24499 
24500  // Specify the processors involved for the creation of the
24501  // shared boundary
24502  Vector<unsigned> processors(2);
24503  processors[0] = iproc;
24504  processors[1] = jproc;
24505  this->Shared_boundary_from_processors[shd_bnd_id] = processors;
24506 
24507  } // for (counter < nshared_bound_iproc_jproc)
24508 
24509  } // else if (iproc == my_rank || jproc == my_rank)
24510 
24511  } // for (jproc < nproc)
24512 
24513  } // for (iproc < nproc)
24514 
24515  // Get the time to create new shared boundaries representations
24516  if (Print_timings_level_load_balance>2)
24517  {
24518  oomph_info << "CPU for creating new shared boundaries representations (load balance) [9.7]: "
24519  <<TimingHelpers::timer()-tt_start_create_new_shared_boundaries_polylines
24520  << std::endl;
24521  }
24522 
24523  // ==================================================================
24524  // END: CREATE THE NEW SHARED BOUNDARIES. DELETE THE OLD SHARED
24525  // BOUNDARIES INFORMATION. FILL THE DATA STRUCTURES WITH THE NEW
24526  // SHARED BOUNDARIES INFO.
24527  // ==================================================================
24528 
24529  // ==================================================================
24530  // BEGIN: SORT THE SHARED BOUNDARIES AND CREATE SHARED CURVES (A SET
24531  // OF CONTIGUOUS SHARED POLYLINES). STORE THEM IN THE GLOBAL
24532  // CONTAINER FOR SHARED BOUNDARIES. FREE MEMORY BY DELETING FACE
24533  // ELEMENTS
24534  // ==================================================================
24535 
24536  // Get the time to create the new shared curves
24537  double tt_start_create_new_shared_curves=0.0;
24538  if (Print_timings_level_load_balance>2)
24539  {
24540  tt_start_create_new_shared_curves=TimingHelpers::timer();
24541  }
24542 
24543  // Sort the polylines and find if they create a contiguous open
24544  // curve
24545  if (unsorted_polylines_pt.size() > 0)
24546  {
24547  // Now that we have all the new unsorted polylines on "my_rank"x
24548  // processor it is time to sort them so they be all contiguous
24549  this->sort_polylines_helper(unsorted_polylines_pt,
24550  this->Shared_boundary_polyline_pt[my_rank]);
24551  }
24552 
24553  // Free the memory allocated for the face elements
24554  for (unsigned iproc = 0; iproc < nproc; iproc++)
24555  {
24556  const unsigned nface_ele = unsorted_face_ele_pt[iproc].size();
24557  for (unsigned e = 0; e < nface_ele; e++)
24558  {
24559  delete unsorted_face_ele_pt[iproc][e];
24560  unsorted_face_ele_pt[iproc][e] = 0;
24561  } // for (e < nface_ele)
24562 
24563  } // for (iproc < nproc)
24564 
24565  // The time to create the new shared curves
24566  if (Print_timings_level_load_balance>2)
24567  {
24568  oomph_info << "CPU for creating the new shared curves (load balance) [9.8]: "
24569  <<TimingHelpers::timer()-tt_start_create_new_shared_curves
24570  << std::endl;
24571  }
24572 
24573  // ==================================================================
24574  // END: SORT THE SHARED BOUNDARIES AND CREATE SHARED CURVES (A SET
24575  // OF CONTIGUOUS SHARED POLYLINES). STORE THEM IN THE GLOBAL
24576  // CONTAINER FOR SHARED BOUNDARIES. FREE MEMORY BY DELETING FACE
24577  // ELEMENTS
24578  // ==================================================================
24579 
24580  }
24581 
24582  //======================================================================
24583  // Computes the degree of the nodes on the shared boundaries, the
24584  // degree of the node is computed from the global graph created by the
24585  // shared boundaries of all processors
24586  //======================================================================
24587  template <class ELEMENT>
24589  compute_shared_node_degree_helper(Vector<Vector<FiniteElement*> >
24590  &unsorted_face_ele_pt,
24591  std::map<Node*, unsigned>
24592  &global_node_degree)
24593  {
24594  // Get the rank and number of processors
24595  const unsigned nproc = this->communicator_pt()->nproc();
24596  const unsigned my_rank = this->communicator_pt()->my_rank();
24597 
24598  // Store a temporary sorting of the nodes, starting from the
24599  // lower-left position
24600  Vector<Vector<Node*> > tmp_sorted_shared_node_pt(nproc);
24601 
24602  // Store the alias of the node, it may be shared by more than two
24603  // processors, they should know that the node is the same
24604  // [0] iproc, processor with which the current processor shared the node
24605  // [1] node #, number of node in the number of nodes shared with iproc
24606  // processor
24607  std::map<Node*, Vector<Vector<unsigned> > > node_alias;
24608 
24609  // Stores the local adjacency matrix
24610  // (nproc*n_shared_nodes*n_shared_nodes)
24611  Vector<Vector<Vector<unsigned> > > local_adjacency_matrix(nproc);
24612 
24613  // Sort the nodes and create the adjacency matrix of each sub-graph
24614  // created by the shared edges
24615  create_adjacency_matrix_new_shared_edges_helper(unsorted_face_ele_pt,
24616  tmp_sorted_shared_node_pt,
24617  node_alias,
24618  local_adjacency_matrix);
24619 
24620  // Prepare the info. to be sent to the root processor, which will be
24621  // in charge of updating the nodes degree by combining the info. of
24622  // all the processors
24623 
24624  // The flat package with the info. to send to root
24625  Vector<unsigned> package_unsigned_send_data_to_root;
24626 
24627  // Encode the info. that will be sent to the root processor
24628 
24629  // Loop over the temporary sorted nodes between each pair of
24630  // processors
24631  for (unsigned iproc = 0; iproc < nproc; iproc++)
24632  {
24633  // Send the processor index
24634  package_unsigned_send_data_to_root.push_back(iproc);
24635 
24636  // Get the number of nodes shared between the processors
24637  const unsigned n_nodes = tmp_sorted_shared_node_pt[iproc].size();
24638 
24639  // Send the number of nodes shared with the iproc processor
24640  package_unsigned_send_data_to_root.push_back(n_nodes);
24641 
24642  // Loop over the nodes
24643  for (unsigned ishd = 0; ishd < n_nodes; ishd++)
24644  {
24645  // Get the node
24646  Node* shd_node_pt = tmp_sorted_shared_node_pt[iproc][ishd];
24647 
24648  // Get the alias info.
24649  Vector<Vector<unsigned> > alias_node_info = node_alias[shd_node_pt];
24650 
24651  // Get the number of alias for the node
24652  const unsigned n_alias = alias_node_info.size();
24653 
24654  // Send the number of alias assigned to the node
24655  package_unsigned_send_data_to_root.push_back(n_alias);
24656 
24657  // Loop over the alias to include them in the package
24658  for (unsigned i = 0; i < n_alias; i++)
24659  {
24660  // Send the alias info.
24661  // The current processor
24662  package_unsigned_send_data_to_root.push_back(alias_node_info[i][0]);
24663  // The prociesso with which is shared
24664  package_unsigned_send_data_to_root.push_back(alias_node_info[i][1]);
24665  // The index of the node
24666  package_unsigned_send_data_to_root.push_back(alias_node_info[i][2]);
24667  } // for (i < n_alias)
24668 
24669  } // for (ishd < n_nodes)
24670 
24671  // Now send the adjacency matrix
24672  for (unsigned i = 0; i < n_nodes; i++)
24673  {
24674  for (unsigned j = 0; j < n_nodes; j++)
24675  {
24676  // Package the adjacency matrix
24677  package_unsigned_send_data_to_root.
24678  push_back(local_adjacency_matrix[iproc][i][j]);
24679 
24680  } // for (j < n_nodes)
24681 
24682  } // for (i < n_nodes)
24683 
24684  } // for (iproc < nproc)
24685 
24686  // Define the root processor
24687  const unsigned root_processor = 0;
24688 
24689  // Get the communicator of the mesh
24690  OomphCommunicator* comm_pt = this->communicator_pt();
24691 
24692  // Number of data send. from this processor to root processor
24693  unsigned n_unsigned_data_send_to_root =
24694  package_unsigned_send_data_to_root.size();
24695 
24696  // Store the number of data to receive from each processor in root
24697  Vector<int> n_unsigned_data_received_in_root(nproc, 0);
24698 
24699  // Send the number of data that each processor will send to root
24700  // Gather the info. in the "root_processor"
24701  MPI_Gather(&n_unsigned_data_send_to_root, // Info. sent from
24702  // each processor
24703  1, // Total number of data to send from each processor
24704  MPI_UNSIGNED,
24705  &n_unsigned_data_received_in_root[0], // Container where
24706  // to receive the
24707  // info. from all
24708  // the processors
24709  1, // Number of data to receive from each processor
24710  MPI_UNSIGNED,
24711  root_processor, // The processor that receives all the
24712  // info.
24713  comm_pt->mpi_comm());
24714 
24715  // Compute the total number of data to receive from all processors
24716  unsigned n_unsigned_total_data_receive_in_root = 0;
24717  for (unsigned iproc = 0; iproc < nproc; iproc++)
24718  {
24719  // Add the number of data to receive from each processor
24720  n_unsigned_total_data_receive_in_root+=
24721  n_unsigned_data_received_in_root[iproc];
24722  }
24723 
24724  // Compute the offsets from each processor
24725  Vector<int> root_unsigned_offsets_receive(nproc,0);
24726  root_unsigned_offsets_receive[0] = 0;
24727  for (unsigned iproc = 1; iproc < nproc; iproc++)
24728  {
24729  // Compute the offset to store the values received from each
24730  // processor
24731  root_unsigned_offsets_receive[iproc] =
24732  root_unsigned_offsets_receive[iproc-1] +
24733  n_unsigned_data_received_in_root[iproc-1];
24734  }
24735 
24736  // Create at least one entry so we don't get a seg fault below
24737  if (package_unsigned_send_data_to_root.size()==0)
24738  {
24739  package_unsigned_send_data_to_root.resize(1);
24740  }
24741 
24742  // Vector where to receive the data sent from each processor
24743  Vector<unsigned>
24744  package_unsigned_data_received_root(n_unsigned_total_data_receive_in_root);
24745  if (my_rank!=root_processor)
24746  {
24747  // Create at least one entry so we don't get a seg fault below
24748  if (package_unsigned_data_received_root.size()==0)
24749  {
24750  package_unsigned_data_received_root.resize(1);
24751  }
24752  } // if (my_rank!=root_processor)
24753 
24754  // Gather the info. from all processors
24755  MPI_Gatherv(&package_unsigned_send_data_to_root[0], // Flat package
24756  // to send
24757  // info. from
24758  // each
24759  // processor
24760  n_unsigned_data_send_to_root, // Total number of data to
24761  // send from each
24762  // processor
24763  MPI_UNSIGNED,
24764  &package_unsigned_data_received_root[0], // Container
24765  // where to
24766  // receive the
24767  // info. from
24768  // all the
24769  // processors
24770  &n_unsigned_data_received_in_root[0], // Number of data
24771  // to receive from
24772  // each processor
24773  &root_unsigned_offsets_receive[0], // The offset to
24774  // store the
24775  // info. from each
24776  // processor
24777  MPI_UNSIGNED,
24778  root_processor, //The processor that receives all the
24779  //info.
24780  comm_pt->mpi_comm());
24781 
24782  // Store the info. to be sent by root to other processors
24783  Vector<unsigned> package_unsigned_data_sent_from_root;
24784  // Total data sent to each processor from root
24785  Vector<int> n_unsigned_data_sent_from_root(nproc, 0);
24786 
24787  // The root processor now has all the info. regarding the shared
24788  // nodes and the adjacency matrix of each pair of processors
24789  if (my_rank == root_processor)
24790  {
24791  // Decode the info. received from all processors
24792  // Counter to decode the info.
24793  unsigned decode_counter = 0;
24794 
24795  // Store the local alias of the nodes in each processor
24796  // [x][][][][] iproc
24797  // [][x][][][] jproc
24798  // [][][x][][] inode
24799  // [][][][x][] ialias
24800  // [][][][][x] alias_data
24801  Vector<Vector<Vector<Vector<Vector<unsigned> > > > >
24802  local_node_alias(nproc);
24803  // Store the local adjacency matrix of each processor
24804  Vector<Vector<Vector<Vector<unsigned> > > > local_adjacency_matrix(nproc);
24805 
24806  // Loop over all the processors
24807  for (unsigned iproc = 0; iproc < nproc; iproc++)
24808  {
24809  local_node_alias[iproc].resize(nproc);
24810 
24811  // Resize the local adjacency matrix to store the info. sent
24812  // from all processors
24813  local_adjacency_matrix[iproc].resize(nproc);
24814 
24815  if (n_unsigned_data_received_in_root[iproc] > 0)
24816  {
24817  // Loop over all the processors to decode the info. received
24818  // from each one
24819  for (unsigned jproc = 0; jproc < nproc; jproc++)
24820  {
24821  // Read the processor number to which the info. correspond
24822  const unsigned read_jproc =
24823  package_unsigned_data_received_root[decode_counter++];
24824 
24825  // The read processor must be the same as the jproc, if that
24826  // is not the case then there is a synchronisation issue
24827  if (read_jproc != jproc)
24828  {
24829  std::ostringstream error_stream;
24830  error_stream
24831  << "The read processor is different from the jproc, this is\n"
24832  << "a synchronisation issue. The data are not read in the\n"
24833  << "sameorder as the were packaged\n"
24834  << "Read processor: (" << read_jproc << ")\n"
24835  << "Current jproc: (" << jproc << ")\n\n";
24836  throw OomphLibError(error_stream.str(),
24837  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
24838  OOMPH_EXCEPTION_LOCATION);
24839  }
24840 
24841  // Read the number of nodes in the shared boundaries between
24842  // iproc and jproc
24843  const unsigned read_n_shd_nodes_iproc_jproc =
24844  package_unsigned_data_received_root[decode_counter++];
24845 
24846  // Resize the container
24847  local_node_alias[iproc][jproc].resize(read_n_shd_nodes_iproc_jproc);
24848 
24849  // Loop over the number of nodes shared between iproc and
24850  // jproc
24851  for (unsigned ishd = 0; ishd < read_n_shd_nodes_iproc_jproc; ishd++)
24852  {
24853  // Read the number of alias of the current ishd node
24854  const unsigned read_n_alias_node_iproc_jproc =
24855  package_unsigned_data_received_root[decode_counter++];
24856 
24857  // Resize the container
24858  local_node_alias[iproc][jproc][ishd].
24859  resize(read_n_alias_node_iproc_jproc);
24860 
24861  for (unsigned ialias = 0;
24862  ialias < read_n_alias_node_iproc_jproc; ialias++)
24863  {
24864  // Resize the container, we know there are three data to
24865  // define the alias of a node
24866  local_node_alias[iproc][jproc][ishd][ialias].resize(3);
24867 
24868  // The 1st processor with which is shared
24869  local_node_alias[iproc][jproc][ishd][ialias][0] =
24870  package_unsigned_data_received_root[decode_counter++];
24871 
24872  // The 2nd processor with which is shared
24873  local_node_alias[iproc][jproc][ishd][ialias][1] =
24874  package_unsigned_data_received_root[decode_counter++];
24875 
24876  // The index of the node in the interaction iproc-jproc
24877  local_node_alias[iproc][jproc][ishd][ialias][2] =
24878  package_unsigned_data_received_root[decode_counter++];
24879 
24880  } // for (ialias < read_n_alias_node_iproc_jproc)
24881 
24882  } // for (ishd < read_n_shd_nodes_iproc_jproc)
24883 
24884  // Resize the local adjacency matrix
24885  local_adjacency_matrix[iproc][jproc].
24886  resize(read_n_shd_nodes_iproc_jproc);
24887  // Read the adjacency matrix sent to root processor
24888  for (unsigned i = 0; i < read_n_shd_nodes_iproc_jproc; i++)
24889  {
24890  // Resize the local adjacency matrix
24891  local_adjacency_matrix[iproc][jproc][i].
24892  resize(read_n_shd_nodes_iproc_jproc);
24893  for (unsigned j = 0; j < read_n_shd_nodes_iproc_jproc; j++)
24894  {
24895  // Read the adjacency matrix entry
24896  local_adjacency_matrix[iproc][jproc][i][j] =
24897  package_unsigned_data_received_root[decode_counter++];
24898  } // for (j < read_n_shd_nodes_iproc_jproc)
24899 
24900  } // for (i < read_n_shd_nodes_iproc_jproc)
24901 
24902  } // for (jproc < nproc)
24903 
24904  } // for (iproc < nproc)
24905 
24906  } // for (iproc < nproc)
24907 
24908 #ifdef PARANOID
24909  if (decode_counter != n_unsigned_total_data_receive_in_root)
24910  {
24911  std::ostringstream error_stream;
24912  error_stream
24913  << "The number of data decoded in root received from others\n"
24914  << "processors is different from the total number of data received\n"
24915  << "Data decoded: (" << decode_counter << ")\n"
24916  << "Data received: ("<<n_unsigned_total_data_receive_in_root<<")\n\n"
24917  << "This is a synchronisation issue so you are probably sending\n"
24918  << "more or less info. than the one that is being decoded\n\n";
24919  throw OomphLibError(error_stream.str(),
24920  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
24921  OOMPH_EXCEPTION_LOCATION);
24922  }
24923 #endif
24924 
24925  // Assign a unique id to the nodes (uses the alias information to
24926  // identify the repetition of a node in other processors). The
24927  // global node id is given by the position (index) in the global
24928  // node alias
24929 
24930  // Keep track of those alias already assigned a unique id
24931  std::map<Vector<unsigned>, bool> alias_done;
24932 
24933  // Store all the alias associated to each node
24934  Vector<Vector<Vector<unsigned> > > global_node_alias;
24935 
24936  // Loop over all the processors
24937  for (unsigned iproc = 0; iproc < nproc; iproc++)
24938  {
24939  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
24940  {
24941  // Read the number of nodes shared between the processors
24942  const unsigned n_shd_nodes_iproc_jproc =
24943  local_node_alias[iproc][jproc].size();
24944 #ifdef PARANOID
24945  // Read the number of nodes shared in the other direction
24946  const unsigned n_shd_nodes_jproc_iproc =
24947  local_node_alias[jproc][iproc].size();
24948 
24949  if (n_shd_nodes_iproc_jproc != n_shd_nodes_jproc_iproc)
24950  {
24951  std::ostringstream error_stream;
24952  error_stream
24953  << "The number of nodes shared between iproc and jproc is\n"
24954  << "different from the number of nodes shared between jproc\n"
24955  << "and iproc\n"
24956  << "Nodes shared between processor (" << iproc << ") and "
24957  << "processor ("<<jproc<<"): ("<<n_shd_nodes_iproc_jproc<<")\n"
24958  << "Nodes shared between processor (" << jproc << ") and "
24959  << "processor ("<<iproc<<"): ("<<n_shd_nodes_jproc_iproc<<")\n\n";
24960  throw OomphLibError(error_stream.str(),
24961  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
24962  OOMPH_EXCEPTION_LOCATION);
24963  } // if (n_shd_nodes_iproc_jproc != n_shd_nodes_jproc_iproc)
24964 #endif
24965 
24966  // Loop over the nodes shared between the processors
24967  for (unsigned ishd = 0; ishd < n_shd_nodes_iproc_jproc; ishd++)
24968  {
24969  // Get the number of alias associated to the node on each
24970  // processor
24971  const unsigned n_alias_iproc_jproc =
24972  local_node_alias[iproc][jproc][ishd].size();
24973  const unsigned n_alias_jproc_iproc =
24974  local_node_alias[jproc][iproc][ishd].size();
24975 
24976  // Store all the found alias to the node
24977  Vector<Vector<unsigned> > node_alias;
24978 
24979  // Flag to indicate if a new alias has been added
24980  bool new_alias_added = false;
24981 
24982  // Start by adding the "direct" alias of the node
24983  for (unsigned ialias = 0; ialias < n_alias_iproc_jproc; ialias++)
24984  {
24985  // Get the alias of the node
24986  Vector<unsigned> current_alias =
24987  local_node_alias[iproc][jproc][ishd][ialias];
24988  // Check if already done
24989  if (!alias_done[current_alias])
24990  {
24991  // Add the alias of the node
24992  node_alias.push_back(current_alias);
24993  // Set the flag to indicate a new alias has been added
24994  new_alias_added = true;
24995  // Mark the alias as done
24996  alias_done[current_alias] = true;
24997  } // if (!alias_done[i_alias])
24998 
24999  } // for (ialias < n_alias_iproc_jproc)
25000 
25001  // Start by adding the "direct" alias of the node
25002  for (unsigned ialias = 0; ialias < n_alias_jproc_iproc; ialias++)
25003  {
25004  // Get the alias of the node
25005  Vector<unsigned> current_alias =
25006  local_node_alias[jproc][iproc][ishd][ialias];
25007 
25008  // Check if already done
25009  if (!alias_done[current_alias])
25010  {
25011  // Add the alias of the node
25012  node_alias.push_back(current_alias);
25013  // Set the flag to indicate a new alias has been added
25014  new_alias_added = true;
25015  // Mark the alias as done
25016  alias_done[current_alias] = true;
25017  } // if (!alias_done[i_alias])
25018 
25019  } // for (ialias < n_alias_jproc_iproc)
25020 
25021  unsigned counter_alias = 0;
25022  // Visit the alias of the node and add any new found
25023  // alias, end until all its alias have been included
25024 
25025  unsigned n_current_alias = node_alias.size();
25026  while(new_alias_added || counter_alias < n_current_alias)
25027  //while(new_alias_added) // we need to check all the alias, including those added during the process
25028  {
25029  new_alias_added = false;
25030  // Store the current visited alias
25031  Vector<unsigned> current_alias = node_alias[counter_alias];
25032 
25033  // Get the alias associated with the current alias
25034  Vector<Vector<unsigned> > alias_of_current_alias =
25035  local_node_alias[current_alias[0]]
25036  [current_alias[1]]
25037  [current_alias[2]];
25038 
25039  // Get all the alias associated with the alias of the
25040  // current alias
25041  const unsigned n_alias = alias_of_current_alias.size();
25042 
25043  // Loop over the new alias and check if require to add
25044  // them
25045  for (unsigned k = 0; k < n_alias; k++)
25046  {
25047  // Get the alias of the node
25048  Vector<unsigned> add_alias =
25049  alias_of_current_alias[k];
25050 
25051  // Check if already done
25052  if (!alias_done[add_alias])
25053  {
25054  // Add the alias of the node
25055  node_alias.push_back(add_alias);
25056  // Set the flag to indicate a new alias has been
25057  // added
25058  new_alias_added = true;
25059  // Mark the alias ad done
25060  alias_done[add_alias] = true;
25061  } // if (!alias_done[i_alias])
25062 
25063  } // for (k < n_alias)
25064 
25065  // Get the alias associated with the current alias (in the
25066  // other direction)
25067  Vector<Vector<unsigned> > alias_of_current_alias2 =
25068  local_node_alias[current_alias[1]]
25069  [current_alias[0]]
25070  [current_alias[2]];
25071 
25072  // Get all the alias associated with the current alias
25073  // (in the other direction)
25074  const unsigned n_alias2 = alias_of_current_alias2.size();
25075 
25076  // Loop over the new alias and check if require to add
25077  // them
25078  for (unsigned k = 0; k < n_alias2; k++)
25079  {
25080  // Get the alias of the node
25081  Vector<unsigned> add_alias =
25082  alias_of_current_alias2[k];
25083 
25084  // Check if already done
25085  if (!alias_done[add_alias])
25086  {
25087  // Add the alias of the node
25088  node_alias.push_back(add_alias);
25089  // Set the flag to indicate a new alias has been
25090  // added
25091  new_alias_added = true;
25092  // Mark the alias ad done
25093  alias_done[add_alias] = true;
25094  } // if (!alias_done[i_alias])
25095 
25096  } // for (k < n_alias)
25097 
25098  // Go for the next alias
25099  counter_alias++;
25100 
25101  // Update the number of alias so that the while stops when
25102  // all the alias have been visited and no new alias was
25103  // added
25104  n_current_alias = node_alias.size();
25105 
25106  } // while(new_alias_added || counter_alias < n_current_alias)
25107 
25108  // If the node has not been previously added, then include
25109  // all its alias
25110  if (node_alias.size() > 0)
25111  {
25112  // Add all the found alias of the node to the global alias
25113  // storage
25114  global_node_alias.push_back(node_alias);
25115  }
25116 
25117  } // for (ishd < n_shd_nodes_iproc_jproc)
25118 
25119  } // for (jproc < nproc)
25120 
25121  } // for (iproc < nproc)
25122 
25123  // We now have the global number of nodes, each with its own id
25124  // (the index in the global_node_alias vector)
25125 
25126  // Get the number of global shared nodes
25127  const unsigned n_global_shared_nodes = global_node_alias.size();
25128 
25129  // Create matrix from local to global shared node id
25130  Vector<Vector<Vector<int> > > local_to_global_shared_node(nproc);
25131 
25132  // Loop over all the processors to resize
25133  for (unsigned iproc = 0; iproc < nproc; iproc++)
25134  {
25135  // Resize the map matrix
25136  local_to_global_shared_node[iproc].resize(nproc);
25137  } // for (iproc < nproc)
25138 
25139  // Loop over all the processors to resize (the third direction,
25140  // required if we want to loop over the half of the matrix only)
25141  for (unsigned iproc = 0; iproc < nproc; iproc++)
25142  {
25143  // Loop over the half of the matrix to resize
25144  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
25145  {
25146  // Read the number of nodes shared between the processors
25147  const unsigned n_shd_nodes =
25148  local_node_alias[iproc][jproc].size();
25149 
25150  // Resize the map matrix
25151  local_to_global_shared_node[iproc][jproc].resize(n_shd_nodes,-1);
25152 
25153  // ... and resize the other half map matrix
25154  local_to_global_shared_node[jproc][iproc].resize(n_shd_nodes,-1);
25155 
25156  } // for (jproc < nproc)
25157 
25158  } // for (iproc < nproc)
25159 
25160  // Fill the matrix for mapping from local to global node id
25161 
25162  // Loop over the global nodes, and for each alias assign the
25163  // corresponding global node id
25164  for (unsigned k = 0 ; k < n_global_shared_nodes; k++)
25165  {
25166  // Get the number of alias associated to the current global node
25167  const unsigned n_alias_global_node = global_node_alias[k].size();
25168  // Loop over the alias and assign the global node id
25169  for (unsigned l = 0; l < n_alias_global_node; l++)
25170  {
25171  // Get the 1st processor
25172  const unsigned iproc = global_node_alias[k][l][0];
25173  // Get the 2nd processor
25174  const unsigned jproc = global_node_alias[k][l][1];
25175  // Get the node number
25176  const unsigned ishd = global_node_alias[k][l][2];
25177  // Assign the global node id
25178  local_to_global_shared_node[iproc][jproc][ishd] = k;
25179 
25180  } // for (l < n_alias_global_node)
25181 
25182  } // for (k < n_global_shared_nodes)
25183 
25184  // Create the global adjacency matrix
25185  Vector<Vector<unsigned> > global_adjacency_matrix(n_global_shared_nodes);
25186  // Resize the global adjacency matrix
25187  for (unsigned k = 0; k < n_global_shared_nodes; k++)
25188  {
25189  // Resize
25190  global_adjacency_matrix[k].resize(n_global_shared_nodes,0);
25191  } // for (k < n_global_shared_nodes)
25192 
25193  // Add the entries to the global adjacency matrix and compute the
25194  // degree of each node
25195 
25196  // Store the degree of the global nodes
25197  Vector<unsigned> global_node_degree(n_global_shared_nodes, 0);
25198 
25199  // Loop over the processors
25200  for (unsigned iproc = 0; iproc < nproc; iproc++)
25201  {
25202  // Loop over the half of the matrix to resize
25203  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
25204  {
25205  // Get the number of nodes shared between the processors
25206  const unsigned n_shd_nodes =
25207  local_node_alias[iproc][jproc].size();
25208 
25209  // Search for entries in the local adjacency matrix that set a
25210  // connection among the nodes
25211 
25212  // Loop over the shared nodes in the current pair of
25213  // processors
25214  for (unsigned ishd = 0; ishd < n_shd_nodes; ishd++)
25215  {
25216  for (unsigned jshd = ishd + 1; jshd < n_shd_nodes; jshd++)
25217  {
25218  // Are the nodes associated
25219  if (local_adjacency_matrix[iproc][jproc][ishd][jshd] > 0)
25220  {
25221  // Get the global nodes id
25222 
25223  // Get the "left-node" global id
25224  const int global_shd_node_left =
25225  local_to_global_shared_node[iproc][jproc][ishd];
25226 
25227  // Get the "right-node" global id
25228  const int global_shd_node_right =
25229  local_to_global_shared_node[iproc][jproc][jshd];
25230 
25231 #ifdef PARANOID
25232  // Check if the local nodes have a global node
25233  // associated
25234  if (global_shd_node_left == -1)
25235  {
25236  std::ostringstream error_stream;
25237  error_stream
25238  << "The local node in processors iproc and jproc has no\n"
25239  << "global node assigned\n"
25240  << "iproc processor: (" << iproc << ")\n"
25241  << "jproc processor: ("<<jproc<<")\n"
25242  << "Local node: (" << ishd << ")\n\n";
25243  throw OomphLibError(error_stream.str(),
25244  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25245  OOMPH_EXCEPTION_LOCATION);
25246  }
25247 
25248  // Check if the local nodes have a global node
25249  // associated
25250  if (global_shd_node_right == -1)
25251  {
25252  std::ostringstream error_stream;
25253  error_stream
25254  << "The local node in processors iproc and jproc has no\n"
25255  << "global node assigned\n"
25256  << "iproc processor: (" << iproc << ")\n"
25257  << "jproc processor: ("<<jproc<<")\n"
25258  << "Local node: (" << jshd << ")\n\n";
25259  throw OomphLibError(error_stream.str(),
25260  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25261  OOMPH_EXCEPTION_LOCATION);
25262  }
25263 #endif
25264  // Get the unsigned version of the indexes
25265  const unsigned uleft =
25266  static_cast<unsigned>(global_shd_node_left);
25267  const unsigned uright =
25268  static_cast<unsigned>(global_shd_node_right);
25269 
25270  // Add the entry in the global adjacency matrix
25271  global_adjacency_matrix[uleft][uright]++;
25272 
25273  // ... and in the other direction too
25274  global_adjacency_matrix[uright][uleft]++;
25275 
25276  // Add on to the degree of the left node
25277  global_node_degree[uleft]++;
25278 
25279  // Add on to the degree of the right node
25280  global_node_degree[uright]++;
25281 
25282  } // if (local_adjacency_matrix[iproc][jproc][ishd][jshd] > 0)
25283 
25284  } // // for (jshd < n_shd_nodes)
25285 
25286  } // for (ishd < n_shd_nodes)
25287 
25288  } // for (jproc < nproc)
25289 
25290  } // for (iproc < nproc)
25291 
25292  // Assign the global degree to the shared nodes between each pair
25293  // of processors
25294  Vector<Vector<Vector<unsigned> > > root_local_node_degree(nproc);
25295  // Resize the container
25296  for (unsigned iproc = 0; iproc < nproc; iproc++)
25297  {
25298  root_local_node_degree[iproc].resize(nproc);
25299  }
25300 
25301  // Loop over the processors and visited their shared nodes
25302  for (unsigned iproc = 0; iproc < nproc; iproc++)
25303  {
25304  // Only visit the half of the data
25305  for (unsigned jproc = iproc + 1; jproc < nproc; jproc++)
25306  {
25307  // Get the number of shared nodes between this pair of
25308  // processors (iproc, jproc)
25309  const unsigned n_shd_nodes = local_node_alias[iproc][jproc].size();
25310 
25311  // Resize the container to store the local degree of the nodes
25312  root_local_node_degree[iproc][jproc].resize(n_shd_nodes);
25313  // ... and in the other way too
25314  root_local_node_degree[jproc][iproc].resize(n_shd_nodes);
25315 
25316  // Loop over the number of nodes shared between the pair of
25317  // processors
25318  for (unsigned ishd = 0; ishd < n_shd_nodes; ishd++)
25319  {
25320  // Get the global node id for the current shared node
25321  const int global_shd_node_id =
25322  local_to_global_shared_node[iproc][jproc][ishd];
25323 
25324 #ifdef PARANOID
25325  // Check if the local nodes have a global node associated
25326  if (global_shd_node_id == -1)
25327  {
25328  std::ostringstream error_stream;
25329  error_stream
25330  << "The local node in processors iproc and jproc has no\n"
25331  << "global node assigned\n"
25332  << "iproc processor: (" << iproc << ")\n"
25333  << "jproc processor: ("<<jproc<<")\n"
25334  << "Local node: (" << ishd << ")\n\n";
25335  throw OomphLibError(error_stream.str(),
25336  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25337  OOMPH_EXCEPTION_LOCATION);
25338  }
25339 #endif
25340 
25341  // Get the unsigned version of the global index
25342  const unsigned uglobal_shd_node_id =
25343  static_cast<unsigned>(global_shd_node_id);
25344 
25345  // Get the degree of the node
25346  const unsigned node_degree =
25347  global_node_degree[uglobal_shd_node_id];
25348 
25349  // Set the degree in the container for the degree of the
25350  // nodes in the local interaction between processors
25351  root_local_node_degree[iproc][jproc][ishd] = node_degree;
25352  // ... and in the other way too
25353  root_local_node_degree[jproc][iproc][ishd] = node_degree;
25354 
25355  } // for (ishd < n_shd_nodes)
25356 
25357  } // for (jproc < nproc)
25358 
25359  } // for (iproc < nproc)
25360 
25361  // Clear the container where the info. will be sent back to each
25362  // processor
25363  package_unsigned_data_sent_from_root.clear();
25364 
25365  // Prepare the data to sent it back to each processor (encode the
25366  // info. to sent to all processors)
25367  for (unsigned iproc = 0; iproc < nproc; iproc++)
25368  {
25369  // Count the number of data sent to iproc processor
25370  unsigned count_n_data_sent_to_iproc = 0;
25371  for (unsigned jproc = 0; jproc < nproc; jproc++)
25372  {
25373  // No shared nodes between the same processor
25374  if (iproc != jproc)
25375  {
25376  // Get the number of nodes shared between the processors
25377  const unsigned n_shd_nodes =
25378  root_local_node_degree[iproc][jproc].size();
25379 
25380  // Add the number of data sent to iproc processor
25381  count_n_data_sent_to_iproc+=n_shd_nodes;
25382 
25383  // Loop over the nodes shared between the pair of processors
25384  for (unsigned ishd = 0; ishd < n_shd_nodes; ishd++)
25385  {
25386  package_unsigned_data_sent_from_root.
25387  push_back(root_local_node_degree[iproc][jproc][ishd]);
25388  } // for (ishd < n_shd_nodes)
25389 
25390  } // if (iproc != jproc)
25391 
25392  } // for (jproc < nproc)
25393 
25394  // Set the number of data sent to iproc processor
25395  n_unsigned_data_sent_from_root[iproc] = count_n_data_sent_to_iproc;
25396 
25397  } // for (iproc < nproc)
25398 
25399  } // if (my_rank == root_processor)
25400 
25401  // Total data received from root to this processor
25402  int n_unsigned_data_received_from_root = 0;
25403 
25404  // Get the number of data that each processor receives from root
25405  MPI_Scatter(&n_unsigned_data_sent_from_root[0], // Info. sent from
25406  // root to each
25407  // processor
25408  1, // The number of data sent from root to each
25409  // processor
25410  MPI_UNSIGNED,
25411  &n_unsigned_data_received_from_root, // Store the
25412  // info. received
25413  // from root
25414  1, // The number of data received from root
25415  MPI_UNSIGNED,
25416  root_processor, // The processor that sends the
25417  // info.
25418  comm_pt->mpi_comm());
25419 
25420  // Receive the info. sent by root
25421  Vector<unsigned>
25422  package_unsigned_data_received_from_root(n_unsigned_data_received_from_root);
25423 
25424  // Compute the offsets to each processor
25425  Vector<int> root_unsigned_offsets_sent(nproc,0);
25426  root_unsigned_offsets_sent[0] = 0;
25427  for (unsigned iproc = 1; iproc < nproc; iproc++)
25428  {
25429  // Compute the offset to send the values to each processor
25430  root_unsigned_offsets_sent[iproc] =
25431  root_unsigned_offsets_sent[iproc-1] +
25432  n_unsigned_data_sent_from_root[iproc-1];
25433  }
25434 
25435  if (my_rank!=root_processor)
25436  {
25437  // Create at least one entry so we don't get a seg fault below
25438  if (package_unsigned_data_sent_from_root.size()==0)
25439  {
25440  package_unsigned_data_sent_from_root.resize(1);
25441  }
25442  } // if (my_rank!=root_processor)
25443 
25444  // Create at least one entry so we don't get a seg fault below
25445  if (package_unsigned_data_received_from_root.size()==0)
25446  {
25447  package_unsigned_data_received_from_root.resize(1);
25448  }
25449 
25450  // Get the data from root
25451  MPI_Scatterv(&package_unsigned_data_sent_from_root[0], // The
25452  // info. sent
25453  // from root
25454  // to others
25455  // processors
25456  &n_unsigned_data_sent_from_root[0], // The number of
25457  // data sent from
25458  // root to others
25459  // processors
25460  &root_unsigned_offsets_sent[0], // The offsets to each
25461  // processors
25462  MPI_UNSIGNED,
25463  &package_unsigned_data_received_from_root[0], // The
25464  // storage
25465  // in the
25466  // processor
25467  // that
25468  // receives
25469  // the
25470  // info.
25471  n_unsigned_data_received_from_root, // The number of
25472  // data that the
25473  // current
25474  // processor
25475  // receives from
25476  // root
25477  MPI_UNSIGNED,
25478  root_processor, // The root processors
25479  comm_pt->mpi_comm());
25480 
25481  // Decode the info.
25482 
25483  // Keep track of the already nodes done
25484  std::map<Node*, bool> node_done;
25485 
25486  // Read the global degree assigned to the shared nodes between the
25487  // current processors and the other processors
25488  int decode_counter = 0;
25489  // Store the global degree of the local nodes
25490  Vector<Vector<unsigned> > local_node_degree(nproc);
25491  // Loop over the processors
25492  for (unsigned iproc = 0; iproc < nproc; iproc++)
25493  {
25494  // There are no shared nodes with the current processor itself
25495  if (iproc != my_rank)
25496  {
25497  // Get the number of nodes shared with the iproc processor
25498  const unsigned n_nodes = tmp_sorted_shared_node_pt[iproc].size();
25499 
25500  // Read the global degree of the node
25501  package_unsigned_send_data_to_root.push_back(n_nodes);
25502 
25503  // Loop over the nodes
25504  for (unsigned ishd = 0; ishd < n_nodes; ishd++)
25505  {
25506  // Get the node degree assigned to the ishd node in between
25507  // the interaction of the iproc and the current processor
25508  const unsigned node_degree =
25509  package_unsigned_data_received_from_root[decode_counter++];
25510 
25511  // Get the node
25512  Node* shd_node_pt =
25513  tmp_sorted_shared_node_pt[iproc][ishd];
25514 
25515  // Has the node been assigned a global degree
25516  if (!node_done[shd_node_pt])
25517  {
25518  // Assign the global degree to the node
25519  global_node_degree[shd_node_pt] = node_degree;
25520  // Mark the node as done
25521  node_done[shd_node_pt] = true;
25522  }
25523 #ifdef PARANOID
25524  else
25525  {
25526  // The node has been already done, check that the node
25527  // degree is the same as the already assigned
25528  if (global_node_degree[shd_node_pt] != node_degree)
25529  {
25530  std::ostringstream error_stream;
25531  error_stream
25532  << "The local node has already assigned a global degree,\n"
25533  << "however, a different degree for the same node has been\n"
25534  << "read from the data sent from root processor\n"
25535  << "iproc processor: (" << iproc << ")\n"
25536  << "Local node: (" << ishd << ")\n"
25537  << "---------------------------------------------------------\n"
25538  << "Already assigned degree: ("
25539  << global_node_degree[shd_node_pt] << ")\n"
25540  << "New found degree: (" << node_degree << ")\n"
25541  << "---------------------------------------------------------\n"
25542  << "Node coordinates: (" << shd_node_pt->x(0) << ", "
25543  << shd_node_pt->x(1) << ")\n\n";
25544  throw OomphLibError(error_stream.str(),
25545  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25546  OOMPH_EXCEPTION_LOCATION);
25547  }
25548 
25549  } // else if (!node_done[shd_node_pt])
25550 #endif // #ifdef PARANOID
25551 
25552  } // for (ishd < n_nodes)
25553 
25554  } // if (iproc != my_rank)
25555 
25556  } // for (iproc < nproc)
25557 
25558 #ifdef PARANOID
25559  // Ensure that all the info. sent from root processor has been read
25560  if (decode_counter != n_unsigned_data_received_from_root)
25561  {
25562  std::ostringstream error_stream;
25563  error_stream
25564  << "The number of data decoded received from root processor is\n"
25565  << "different from the total number of data received from the root\n"
25566  << "processor\n"
25567  << "Data decoded: (" << decode_counter << ")\n"
25568  << "Data received: ("<<n_unsigned_data_received_from_root<<")\n\n"
25569  << "This is a synchronisation issue so you are probably sending\n"
25570  << "more or less info. than the one that is being decoded\n\n";
25571  throw OomphLibError(error_stream.str(),
25572  "RefineableTriangleMesh::compute_shared_node_degree_helper()",
25573  OOMPH_EXCEPTION_LOCATION);
25574  }
25575 #endif
25576 
25577  }
25578 
25579  //======================================================================
25580  // Sort the nodes on the new shared boundaries (after load balancing),
25581  // computes the alias of the nodes and creates the adjacency matrix
25582  // that represent the graph created by the shared edges between each
25583  // pair of processors
25584  // ======================================================================
25585  template <class ELEMENT>
25588  Vector<Vector<FiniteElement*> > &unsorted_face_ele_pt,
25589  Vector<Vector<Node*> > &tmp_sorted_shared_node_pt,
25590  std::map<Node*, Vector<Vector<unsigned> > > &node_alias,
25591  Vector<Vector<Vector<unsigned> > > &adjacency_matrix)
25592  {
25593  // Get the number of processors and the rank
25594  const unsigned nproc = this->communicator_pt()->nproc();
25595  const unsigned my_rank = this->communicator_pt()->my_rank();
25596 
25597  // Assign a unique id to each node shared between each pair of
25598  // processors, in this case the current processor and the iproc
25599 
25600  // ... also compute the alias of each node (processor and index of
25601  // the node in all processors where it appears)
25602 
25603  // Clear the alias info
25604  node_alias.clear();
25605 
25606  // Temporary storage for the index of the nodes
25607  Vector<std::map<Node*, unsigned> > tmp_node_index(nproc);
25608 
25609  // Loop over the processors
25610  for (unsigned iproc = 0; iproc < nproc; iproc++)
25611  {
25612  // There is no shared elements between the same processor
25613  if (iproc != my_rank)
25614  {
25615  // Map to mark those nodes already visited
25616  std::map<Node*, bool> done_node;
25617 
25618  // A map is used to sort the nodes using their coordinates as
25619  // the key of the map
25620  //std::map<std::pair<double, double>, Node*> sorted_nodes_pt;
25621  std::map<std::pair<double, double>, Node*, classcomp> sorted_nodes_pt;
25622 
25623  // Get the number of unsorted face elements
25624  const unsigned n_unsorted_face_ele =
25625  unsorted_face_ele_pt[iproc].size();
25626 
25627  // Loop over the unsorted elements
25628  for (unsigned e = 0; e < n_unsorted_face_ele; e++)
25629  {
25630  // Get a root element
25631  FiniteElement* face_ele_pt = unsorted_face_ele_pt[iproc][e];
25632  // Get the left node of the face element
25633  Node* left_node_pt = face_ele_pt->node_pt(0);
25634 
25635  // Check if the node has been already sorted in the
25636  // interaction between the current processor and iproc
25637  // processor
25638  if (!done_node[left_node_pt])
25639  {
25640  std::pair<double, double> vertex =
25641  std::make_pair(left_node_pt->x(0), left_node_pt->x(1));
25642  sorted_nodes_pt[vertex] = left_node_pt;
25643  // Mark the node as done
25644  done_node[left_node_pt] = true;
25645  }
25646 
25647  // Get the number of nodes of the face element
25648  const unsigned n_nodes = face_ele_pt->nnode();
25649  // Get the right node of the face element
25650  Node* right_node_pt = face_ele_pt->node_pt(n_nodes-1);
25651 
25652  // Check if the node has been already sorted in the
25653  // interaction between the current processor and iproc
25654  // processor
25655  if (!done_node[right_node_pt])
25656  {
25657  std::pair<double, double> vertex =
25658  std::make_pair(right_node_pt->x(0), right_node_pt->x(1));
25659  sorted_nodes_pt[vertex] = right_node_pt;
25660  // Mark the node as done
25661  done_node[right_node_pt] = true;
25662  }
25663 
25664  } // for (e < nunsorted_face_ele)
25665 
25666  // The nodes are already sorted, we need to return them in the
25667  // proper container
25668 
25669  // The counter to enumerate the nodes
25670  unsigned counter = 0;
25671 
25672  // Go through the map container which already have the nodes
25673  // sorted they have the same sorting on all processors
25674  for (std::map<std::pair<double, double>, Node*>::iterator it
25675  = sorted_nodes_pt.begin(); it != sorted_nodes_pt.end(); it++)
25676  {
25677  // Get the node
25678  Node* node_pt = (*it).second;
25679  // Store the node at the corresponding index
25680  tmp_sorted_shared_node_pt[iproc].push_back(node_pt);
25681 
25682  // Create the temporary access to the node index
25683  tmp_node_index[iproc][node_pt] = counter;
25684 
25685  // Fill the info. for the node alias
25686  Vector<unsigned> alias(3);
25687  // The current processor
25688  alias[0] = my_rank;
25689  // The processor with which is shared
25690  alias[1] = iproc;
25691  // The index with that processor
25692  alias[2] = counter++;
25693 
25694  // Store the info. of the alias
25695  node_alias[node_pt].push_back(alias);
25696 
25697  } // Loop map
25698 
25699  } // if (iproc != my_rank)
25700 
25701  } // for (iproc < nproc)
25702 
25703  // Loop over the processors to resize and initialize the adjacency
25704  // matrix
25705  for (unsigned iproc = 0 ; iproc < nproc; iproc++)
25706  {
25707  // Get the number of nodes shared with iproc
25708  const unsigned n_shd_nodes = tmp_sorted_shared_node_pt[iproc].size();
25709  // Resize the adjacency matrix
25710  adjacency_matrix[iproc].resize(n_shd_nodes);
25711  for (unsigned i = 0; i < n_shd_nodes; i++)
25712  {
25713  // Resize the adjacency matrix
25714  adjacency_matrix[iproc][i].resize(n_shd_nodes);
25715 
25716  // Initialize the
25717  for (unsigned j = 0; j < n_shd_nodes; j++)
25718  {
25719  adjacency_matrix[iproc][i][j] = 0;
25720  } // for (j < n_shd_nodes)
25721 
25722  } // for (i < n_shd_nodes)
25723 
25724  } // for (iproc < nproc)
25725 
25726  // Loop over the processors to fill the adjacency matrix
25727  for (unsigned iproc = 0 ; iproc < nproc; iproc++)
25728  {
25729  // There is no shared elements between the same processor
25730  if (iproc != my_rank)
25731  {
25732  // Get the number of unsorted face elements
25733  const unsigned n_unsorted_face_ele =
25734  unsorted_face_ele_pt[iproc].size();
25735 
25736  // Loop over the unsorted elements
25737  for (unsigned e = 0; e < n_unsorted_face_ele; e++)
25738  {
25739  // Get a root element
25740  FiniteElement* face_ele_pt = unsorted_face_ele_pt[iproc][e];
25741  // Get the left node of the face element
25742  Node* left_node_pt = face_ele_pt->node_pt(0);
25743 
25744  // Get the number of nodes of the face element
25745  const unsigned n_nodes = face_ele_pt->nnode();
25746  // Get the right node of the face element
25747  Node* right_node_pt = face_ele_pt->node_pt(n_nodes-1);
25748 
25749  // Get the index of each of the nodes
25750  const unsigned left_node_index = tmp_node_index[iproc][left_node_pt];
25751  const unsigned right_node_index = tmp_node_index[iproc][right_node_pt];
25752 
25753  // Add an entry to the adjacency matrix to indicate the
25754  // association of left and right node
25755  adjacency_matrix[iproc][left_node_index][right_node_index]++;
25756  // ... both directions
25757  adjacency_matrix[iproc][right_node_index][left_node_index]++;
25758 
25759  } // for (e < n_unsorted_face_ele)
25760 
25761  } // if (iproc != my_rank)
25762 
25763  } // for (iproc < nproc)
25764 
25765  }
25766 
25767  //======================================================================
25768  /// \short Get the nodes on the shared boundary (b), these are stored
25769  /// in the segment they belong
25770  //======================================================================
25771  template <class ELEMENT>
25774  const unsigned &shd_bnd_id, Vector<Vector<Node*> > &tmp_segment_nodes)
25775  {
25776  // Clear the data structure were to return the nodes
25777  tmp_segment_nodes.clear();
25778 
25779  // Get the face elements that created the shared boundary from the
25780  // bulk shared boundary elements
25781 
25782 #ifdef PARANOID
25783  // The temporary storage for the halo face elements
25784  Vector<FiniteElement*> halo_shared_face_ele_pt;
25785 #endif
25786  // The temporary storage for the nonhalo face elements
25787  Vector<FiniteElement*> nonhalo_shared_face_ele_pt;
25788 
25789  // Get the number of shared boundary elements associated with the
25790  // current shared boundary
25791  const unsigned nshared_bound_ele =
25792  this->nshared_boundary_element(shd_bnd_id);
25793 
25794  // Loop over the elements in the shared boundary to create the face
25795  // elements
25796  for (unsigned e = 0; e < nshared_bound_ele; e++)
25797  {
25798  // Get the shared boundary element
25799  FiniteElement* bulk_ele_pt =
25800  this->shared_boundary_element_pt(shd_bnd_id, e);
25801 
25802  // Get the face index
25803  int face_index = this->face_index_at_shared_boundary(shd_bnd_id, e);
25804 
25805  // Before adding the new element we need to ensure that the edge
25806  // that this element represents has not been already added
25807  FiniteElement* face_ele_pt =
25808  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
25809 
25810  // Nonhalo element
25811  if (!bulk_ele_pt->is_halo())
25812  {
25813  // Add nonhalo shared face element to the container
25814  nonhalo_shared_face_ele_pt.push_back(face_ele_pt);
25815  }
25816 #ifdef PARANOID
25817  else // halo element
25818  {
25819  // Add halo shared face element to the container
25820  halo_shared_face_ele_pt.push_back(face_ele_pt);
25821  }
25822 #endif
25823 
25824  } // for (e < nshared_bound_ele)
25825 
25826  // Mark the face elements already used
25827  std::map<FiniteElement*, bool> shared_face_done;
25828 
25829  // Get the number of nonhalo face elements
25830  const unsigned nnonhalo_face_shared_ele =
25831  nonhalo_shared_face_ele_pt.size();
25832 
25833  // If we are in PARANOID mode check that there is one halo element
25834  // for each nonhalo element
25835 #ifdef PARANOID
25836  // Get the number of halo face elements
25837  const unsigned nhalo_face_shared_ele =
25838  halo_shared_face_ele_pt.size();
25839 
25840  // The number of nonhalo shared face boundary elements must be the
25841  // half of the total number of shared boundary elements
25842  if (nshared_bound_ele / 2 != nnonhalo_face_shared_ele)
25843  {
25844  std::ostringstream error_message;
25845  error_message
25846  << "The number of shared boundary elements (" << nshared_bound_ele
25847  << ") is not the double\nof the number of unsorted nonhalo shared "
25848  << "face boundary elements (" << nnonhalo_face_shared_ele
25849  << ")\n for the current boundary ("<< shd_bnd_id << ")\n\n";
25850  throw OomphLibError(error_message.str(),
25851  "RefineableTriangleMesh::get_shared_boundary_segment_nodes_helper()",
25852  OOMPH_EXCEPTION_LOCATION);
25853  }
25854 
25855  // The number of halo shared face boundary elements must be the
25856  // half of the total number of shared boundary elements
25857  if (nshared_bound_ele / 2 != nhalo_face_shared_ele)
25858  {
25859  std::ostringstream error_message;
25860  error_message
25861  << "The number of shared boundary elements (" << nshared_bound_ele
25862  << ") is not the double\nof the number of unsorted halo shared "
25863  << "face boundary elements (" << nhalo_face_shared_ele
25864  << ")\n for the current boundary ("<< shd_bnd_id << ")\n\n";
25865  throw OomphLibError(error_message.str(),
25866  "RefineableTriangleMesh::get_shared_boundary_segment_nodes_helper()",
25867  OOMPH_EXCEPTION_LOCATION);
25868  }
25869 
25870  // ------------------------------------------------------------------
25871  // Loop over the nonhalo face elements and look for the halo face
25872  // element at the other side of the shared boundary
25873  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
25874  {
25875  // Get the inh-th face element
25876  FiniteElement* nonhalo_face_ele_pt = nonhalo_shared_face_ele_pt[inh];
25877 
25878  // Get the number of nodes on the face element
25879  const unsigned nnodes_nh = nonhalo_face_ele_pt->nnode();
25880  // Get the first and last node on the element
25881  Node* nh_first_node_pt = nonhalo_face_ele_pt->node_pt(0);
25882  Node* nh_last_node_pt = nonhalo_face_ele_pt->node_pt(nnodes_nh-1);
25883 
25884  // Now find the (halo) face element at the other side of the
25885  // shared boundary
25886  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
25887  {
25888  // Get the ih-th face element
25889  FiniteElement* halo_face_ele_pt = halo_shared_face_ele_pt[ih];
25890 
25891  // Check that the face element has not been done
25892  if (!shared_face_done[halo_face_ele_pt])
25893  {
25894  // Get the number of nodes on the face element
25895  const unsigned nnodes_h = halo_face_ele_pt->nnode();
25896  // Get the first and last node on the element
25897  Node* h_first_node_pt = halo_face_ele_pt->node_pt(0);
25898  Node* h_last_node_pt = halo_face_ele_pt->node_pt(nnodes_h-1);
25899 
25900  // If the nodes are the same then we have found the (halo)
25901  // face element at the other side of the shared boundary
25902  if (nh_first_node_pt == h_first_node_pt &&
25903  nh_last_node_pt == h_last_node_pt)
25904  {
25905  // Mark the face elements as done
25906  shared_face_done[nonhalo_face_ele_pt] = true;
25907  shared_face_done[halo_face_ele_pt] = true;
25908 
25909  // Break the loop for (ih < nhalo_face_shared_ele)
25910  break;
25911  } // if (nh_first_node_pt == h_first_node_pt &&
25912  // nh_last_node_pt == h_last_node_pt)
25913  else if (nh_first_node_pt == h_last_node_pt &&
25914  nh_last_node_pt == h_first_node_pt)
25915  {
25916  // Mark the face elements as done
25917  shared_face_done[nonhalo_face_ele_pt] = true;
25918  shared_face_done[halo_face_ele_pt] = true;
25919 
25920  // Break the loop for (ih < nhalo_face_shared_ele)
25921  break;
25922  } // else if (nh_first_node_pt == h_last_node_pt &&
25923  // nh_last_node_pt == h_first_node_pt)
25924 
25925  } // if (face_done[halo_face_ele_pt])
25926 
25927  } // for (ih < nhalo_face_shared_ele)
25928 
25929  } // for (inh < nnonhalo_face_shared_ele)
25930 
25931  // The number of done shared face elements MUST be the same as the
25932  // sum of the nonhalo and halo shared boundary face elements
25933  if ((nnonhalo_face_shared_ele + nhalo_face_shared_ele) !=
25934  shared_face_done.size())
25935  {
25936  std::ostringstream error_message;
25937  error_message
25938  << "The number of DONE shared boundary face elements ("
25939  << shared_face_done.size() << ") is not the same\n as the sum of"
25940  << "the nonhalo face shared boundary elements ("
25941  << nnonhalo_face_shared_ele << ")\nand the halo face shared "
25942  << "boundary elements ("<< nhalo_face_shared_ele << ") for the\n/"
25943  << "current boundary (" << shd_bnd_id << ")\n\n";
25944  throw OomphLibError(error_message.str(),
25945  "RefineableTriangleMesh::get_shared_boundary_segment_nodes_helper()",
25946  OOMPH_EXCEPTION_LOCATION);
25947  }
25948 #endif // #ifdef PARANOID
25949 
25950  // -------------------------------------------------------------
25951  // Now sort the face elements
25952  // -------------------------------------------------------------
25953 
25954  // We already have the shared face elements that make the shared
25955  // boundary now sort them to create a contiguous boundary
25956 
25957  // Clear the already done face elements
25958  shared_face_done.clear();
25959 
25960  unsigned nsorted_face_ele = 0;
25961 
25962  // Storing for the sorting nodes extracted from the face elements
25963  std::list<Node*> sorted_nodes;
25964 
25965  // Get the root face element
25966  FiniteElement* root_face_ele_pt = nonhalo_shared_face_ele_pt[0];
25967  nsorted_face_ele++;
25968 
25969  // Mark face as done
25970  shared_face_done[root_face_ele_pt] = true;
25971 
25972  // The initial and final node on the list
25973  const unsigned nnodes_root = root_face_ele_pt->nnode();
25974  Node *first_node_pt = root_face_ele_pt->node_pt(0);
25975  Node *last_node_pt = root_face_ele_pt->node_pt(nnodes_root-1);
25976 
25977  // Push back on the list the new nodes
25978  sorted_nodes.push_back(first_node_pt);
25979  sorted_nodes.push_back(last_node_pt);
25980 
25981  // Sort the face elements
25982  while (nsorted_face_ele < nnonhalo_face_shared_ele)
25983  {
25984  // Flag to indicate when a node was added
25985  bool node_added = false;
25986 
25987  // Start from the next edge since we have already added the
25988  // previous one as the initial face element
25989  for (unsigned iface = 1; iface < nnonhalo_face_shared_ele; iface++)
25990  {
25991  FiniteElement* tmp_shared_face_ele_pt =
25992  nonhalo_shared_face_ele_pt[iface];
25993 
25994  // If face has not been sorted
25995  if (!shared_face_done[tmp_shared_face_ele_pt])
25996  {
25997  // Get the number of nodes for the current face element
25998  const unsigned tmp_nnodes = tmp_shared_face_ele_pt->nnode();
25999 
26000  // Get each individual node
26001  Node* left_node_pt = tmp_shared_face_ele_pt->node_pt(0);
26002  Node* right_node_pt = tmp_shared_face_ele_pt->node_pt(tmp_nnodes-1);
26003 
26004  if (left_node_pt == first_node_pt)
26005  {
26006  // Push front the new node
26007  sorted_nodes.push_front(right_node_pt);
26008  first_node_pt = right_node_pt;
26009  node_added = true;
26010  }
26011  else if (left_node_pt == last_node_pt)
26012  {
26013  // Push back the new node
26014  sorted_nodes.push_back(right_node_pt);
26015  last_node_pt = right_node_pt;
26016  node_added = true;
26017  }
26018  else if (right_node_pt == first_node_pt)
26019  {
26020  // Push front the new node
26021  sorted_nodes.push_front(left_node_pt);
26022  first_node_pt = left_node_pt;
26023  node_added = true;
26024  }
26025  else if (right_node_pt == last_node_pt)
26026  {
26027  // Push back the new node
26028  sorted_nodes.push_back(left_node_pt);
26029  last_node_pt = left_node_pt;
26030  node_added = true;
26031  }
26032 
26033  if (node_added)
26034  {
26035  // Mark as done only if one of its nodes has been added to
26036  // the list
26037  shared_face_done[tmp_shared_face_ele_pt] = true;
26038  nsorted_face_ele++;
26039 
26040  // Break the for
26041  break;
26042  }
26043 
26044  } // if (!shared_face_done[tmp_shared_face_ele_pt])
26045 
26046  } // for (iface < nnonhalo_face_shared_ele)
26047 
26048  } // while (nsorted_face_ele < nnonhalo_face_shared_ele))
26049 
26050  // Here we can safely delete the face elements, they are no longer
26051  // required
26052 
26053  // First the nonhalo face elements
26054  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
26055  {
26056  delete nonhalo_shared_face_ele_pt[inh];
26057  nonhalo_shared_face_ele_pt[inh] = 0;
26058  } // for (inh < nnonhalo_face_shared_ele)
26059 
26060 #ifdef PARANOID
26061  // ... then the halo face elements
26062  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
26063  {
26064  delete halo_shared_face_ele_pt[ih];
26065  halo_shared_face_ele_pt[ih] = 0;
26066  } // for (inh < nhalo_face_shared_ele)
26067 #endif
26068 
26069  // ------------------------------------------------
26070  // Now copy the nodes to the output container
26071  // ------------------------------------------------
26072  // Get the number of nodes in the container
26073  const unsigned n_nodes = sorted_nodes.size();
26074 
26075  // First resize the container
26076  tmp_segment_nodes.resize(1);
26077  tmp_segment_nodes[0].resize(n_nodes);
26078 
26079  // Counter
26080  unsigned counter = 0;
26081 
26082  // Loop over the list of nodes and copy them in the output container
26083  for (std::list<Node*>::iterator it = sorted_nodes.begin();
26084  it != sorted_nodes.end(); it++)
26085  {
26086  tmp_segment_nodes[0][counter] = (*it);
26087  counter++;
26088  } // Loop over sorted nodes
26089 
26090  }
26091 
26092  //=====start of get_required_elemental_information_load_balance_helper====
26093  /// \short Helper function to get the required elemental information from
26094  /// the element that will be sent to iproc processor.
26095  /// This info. involves the association of the element to a boundary or
26096  /// region.
26097  //========================================================================
26098  template<class ELEMENT>
26101  unsigned& iproc,
26102  Vector<Vector<FiniteElement*> > &f_haloed_ele_pt,
26103  FiniteElement* ele_pt)
26104  {
26105  // Check if the element is associated with the original boundaries
26106  const unsigned nbound = this->initial_shared_boundary_id();
26107 
26108  // Get the number of processors
26109  const unsigned nproc = this->communicator_pt()->nproc();
26110 
26111  // ------------------------------------------------------------------
26112  // Stores the information regarding the boundaries associated to the
26113  // element (it that is the case)
26114  Vector<unsigned> associated_boundaries;
26115  Vector<unsigned> face_index_on_boundary;
26116 
26117  unsigned counter_face_indexes = 0;
26118 
26119  for (unsigned b = 0; b < nbound; b++)
26120  {
26121  // Get the number of elements associated to boundary i
26122  const unsigned nboundary_ele = nboundary_element(b);
26123  for (unsigned e = 0; e < nboundary_ele; e++)
26124  {
26125  if (ele_pt == this->boundary_element_pt(b,e))
26126  {
26127  // Keep track of the boundaries associated to the element
26128  associated_boundaries.push_back(b);
26129  // Get the face index
26130  face_index_on_boundary.push_back(face_index_at_boundary(b,e));
26131  counter_face_indexes++;
26132 #ifdef PARANOID
26133  if (counter_face_indexes > 2)
26134  {
26135  std::stringstream error_message;
26136  error_message
26137  << "A triangular element can not have more than two of its faces "
26138  << "on a boundary!!!\n\n";
26139  throw OomphLibError(error_message.str(),
26140  "RefineableTriangleMesh::get_required_elemental_information_helper()",
26141  OOMPH_EXCEPTION_LOCATION);
26142  }
26143 #else
26144  // Already found 2 face indexes on the same boundary?
26145  if (counter_face_indexes==2) {break;}
26146 #endif // #ifdef PARANOID
26147 
26148  } // if (ele_pt == this->boundary_element_pt(b,e))
26149 
26150  } // (e < nboundary_ele)
26151 
26152  } // (b < nbound)
26153 
26154  // If the element is associated to any boundary then package all the
26155  // relevant info
26156  const unsigned nassociated_boundaries = associated_boundaries.size();
26157  if (nassociated_boundaries > 0)
26158  {
26159  Flat_packed_unsigneds.push_back(1);
26160 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26161  Flat_packed_unsigneds_string.push_back("The element is a boundary element");
26162 #endif
26163  Flat_packed_unsigneds.push_back(nassociated_boundaries);
26164 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26165  std::stringstream junk;
26166  junk << "The elements is associated to " << nassociated_boundaries << " boundaries";
26167  Flat_packed_unsigneds_string.push_back(junk.str());
26168 #endif
26169 
26170  // Package the ids of the associated boundaries and the
26171  // corresponding face index for each boundary (if the element is a
26172  // corner element, it will have two faces associated to the
26173  // boundary)
26174  for (unsigned i = 0; i < nassociated_boundaries; i++)
26175  {
26176  unsigned b = associated_boundaries[i];
26177  Flat_packed_unsigneds.push_back(b);
26178 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26179  std::stringstream junk;
26180  junk << "Element associated to boundary " << b << " of " << nassociated_boundaries << " total associated boundaries";
26181  Flat_packed_unsigneds_string.push_back(junk.str());
26182 #endif
26183  unsigned f = face_index_on_boundary[i];
26184  Flat_packed_unsigneds.push_back(f);
26185 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26186  std::stringstream junk2;
26187  junk2 << "Face index " << f << " for associated boundary " << b;
26188  Flat_packed_unsigneds_string.push_back(junk2.str());
26189 #endif
26190  }
26191 
26192  // If the element is associated to any boundary then we should
26193  // check if the mesh has regions, if that is the case then we need
26194  // to check to which region the boundary element does belong
26195 
26196  // If the mesh has regions we should look for the element
26197  // associated to a boundary and a specified region
26198  Vector<Vector<unsigned> > associated_boundaries_and_regions;
26199  Vector<unsigned> face_index_on_boundary_and_region;
26200 
26201  // Now check for the case when we have regions in the mesh
26202  const unsigned n_regions = this->nregion();
26203  if (n_regions > 1)
26204  {
26205  // Used to count the number of faces associated with
26206  // boundary-regions
26207  unsigned counter_face_indexes_in_regions = 0;
26208  // Loop over the boundaries
26209  for (unsigned b = 0; b < nbound; b++)
26210  {
26211  // Go through each region by getting the region id
26212  for (unsigned i_reg = 0 ; i_reg < n_regions; i_reg++)
26213  {
26214  // Get thre region id associated with the (i_reg)-th region
26215  const unsigned region_id =
26216  static_cast<unsigned>(this->Region_attribute[i_reg]);
26217 
26218  // Loop over all elements associated with the current boundary
26219  // and the i_reg-th region and check if the element is part of
26220  // any region
26221  const unsigned nele_in_region =
26222  this->nboundary_element_in_region(b, region_id);
26223  for (unsigned ee = 0; ee < nele_in_region; ee++)
26224  {
26225  // Check if the boundary-region element is the same as the
26226  // element
26227  if (ele_pt ==
26228  this->boundary_element_in_region_pt(b, region_id, ee))
26229  {
26230  // Storage for the boundary and region associated to the
26231  // element
26232  Vector<unsigned> bound_and_region(2);
26233 
26234  // Keep track of the boundaries associated to the element
26235  bound_and_region[0] = b;
26236  // Keep track of the regions associated to the element
26237  bound_and_region[1] = region_id;
26238  // Add the boundaries and regions in the storage to be
26239  // sent to other processors
26240  associated_boundaries_and_regions.push_back(bound_and_region);
26241  // Get the face index and keep track of it
26242  face_index_on_boundary_and_region.push_back(
26243  this->face_index_at_boundary_in_region(b,region_id,ee));
26244 
26245  // Increase the number of faces of the element associated
26246  // to boundary-regions
26247  counter_face_indexes_in_regions++;
26248 
26249 #ifdef PARANOID
26250  if (counter_face_indexes_in_regions > 2)
26251  {
26252  std::stringstream error_message;
26253  error_message
26254  << "A triangular element can not have more than two of its\n"
26255  << "faces on a boundary!!!\n\n";
26256  throw OomphLibError(error_message.str(),
26257  "RefineableTriangleMesh::get_required_elemental_information_helper()",
26258  OOMPH_EXCEPTION_LOCATION);
26259  } // if (counter_face_indexes_in_regions > 2)
26260 #endif
26261 
26262  } // The element is a boundary-region element
26263 
26264  } // for (ee < nele_in_region)
26265 
26266  } // for (i_reg < n_regions)
26267 
26268  } // for (b < nbound)
26269 
26270  } // if (n_regions > 1)
26271 
26272  // Now package the info. to be sent to other processors
26273  const unsigned nassociated_boundaries_and_regions =
26274  associated_boundaries_and_regions.size();
26275  if (nassociated_boundaries_and_regions > 0)
26276  {
26277  Flat_packed_unsigneds.push_back(1);
26278 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26279  Flat_packed_unsigneds_string.push_back("The element is associated to boundaries and regions");
26280 #endif
26281 
26282  Flat_packed_unsigneds.push_back(nassociated_boundaries_and_regions);
26283 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26284  std::stringstream junk;
26285  junk << "The element is associated to " << nassociated_boundaries_and_regions << " boundaries-regions";
26286  Flat_packed_unsigneds_string.push_back(junk.str());
26287 #endif
26288 
26289  // Package the ids of the associated boundaries, regions and the
26290  // corresponding face index for each boundary-region (if the
26291  // element is a corner element, it will have two faces
26292  // associated to the boundary-region)
26293  for (unsigned i = 0; i < nassociated_boundaries_and_regions; i++)
26294  {
26295  const unsigned b = associated_boundaries_and_regions[i][0];
26296  Flat_packed_unsigneds.push_back(b);
26297 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26298  std::stringstream junk;
26299  junk << "Element associated to boundary " << b << " of " << nassociated_boundaries_and_regions << " total associated boundaries-regions";
26300  Flat_packed_unsigneds_string.push_back(junk.str());
26301 #endif
26302 
26303  const unsigned r = associated_boundaries_and_regions[i][1];
26304  Flat_packed_unsigneds.push_back(r);
26305 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26306  std::stringstream junk2;
26307  junk2 << "Element associated to region " << r << " of " << nassociated_boundaries_and_regions << " total associated boundaries-regions";
26308  Flat_packed_unsigneds_string.push_back(junk2.str());
26309 #endif
26310 
26311  const unsigned f = face_index_on_boundary_and_region[i];
26312  Flat_packed_unsigneds.push_back(f);
26313 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26314  std::stringstream junk3;
26315  junk3 << "Face index " << f << " for associated boundary-region (" << b << "-" << r << ")";
26316  Flat_packed_unsigneds_string.push_back(junk3.str());
26317 #endif
26318  } // for (i < nassociated_boundaries_and_regions)
26319  } // if (nassociated_boundaries_and_regions > 0)
26320  else
26321  {
26322  Flat_packed_unsigneds.push_back(0);
26323 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26324  Flat_packed_unsigneds_string.push_back("The element is NOT associated to boundaries and regions");
26325 #endif
26326  } // else if (nassociated_boundaries_and_regions > 0)
26327 
26328  }
26329  else
26330  {
26331  Flat_packed_unsigneds.push_back(0);
26332 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26333  Flat_packed_unsigneds_string.push_back("The element is not associated to any original boundary");
26334 #endif
26335  }
26336 
26337  // ------------------------------------------------------------
26338  // Now review if the element is associated to a shared boundary
26339 
26340  // Store the shared boundaries, and therefore the face indexes
26341  // associated to the element
26342  Vector<unsigned> associated_shared_boundaries;
26343  Vector<unsigned> face_index_on_shared_boundary;
26344 
26345  // Get the shared boundaries in this processor
26346  Vector<unsigned> my_rank_shared_boundaries_ids;
26347  this->shared_boundaries_in_this_processor(my_rank_shared_boundaries_ids);
26348 
26349  // Get the number of shared boundaries
26350  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
26351  // Loop over the shared boundaries
26352  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
26353  {
26354  // Get the boundary id
26355  const unsigned sb = my_rank_shared_boundaries_ids[i];
26356 
26357  // Get the number of elements associated to shared boundary sb
26358  const unsigned nboundary_ele = this->nshared_boundary_element(sb);
26359  for (unsigned e = 0; e < nboundary_ele; e++)
26360  {
26361  if (ele_pt == this->shared_boundary_element_pt(sb,e))
26362  {
26363  // Keep track of the boundaries associated to the element
26364  associated_shared_boundaries.push_back(sb);
26365  // Get the face index
26366  face_index_on_shared_boundary.push_back(
26367  this->face_index_at_shared_boundary(sb, e));
26368  }
26369  } // (e < nboundary_ele)
26370  } // (i < nmy_rank_shd_bnd)
26371 
26372  // If the element is associated to a shared boundary then package
26373  // all the relevant info
26374  const unsigned nassociated_shared_boundaries =
26375  associated_shared_boundaries.size();
26376  if (nassociated_shared_boundaries > 0)
26377  {
26378  Flat_packed_unsigneds.push_back(3);
26379 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26380  Flat_packed_unsigneds_string.push_back("The element is a shared boundary element");
26381 #endif
26382  Flat_packed_unsigneds.push_back(nassociated_shared_boundaries);
26383 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26384  std::stringstream junk;
26385  junk << "The elements is associated to " << nassociated_shared_boundaries << "shared boundaries";
26386  Flat_packed_unsigneds_string.push_back(junk.str());
26387 #endif
26388 
26389  // Package the ids of the associated boundaries
26390  for (unsigned i = 0; i < nassociated_shared_boundaries; i++)
26391  {
26392  const unsigned b = associated_shared_boundaries[i];
26393  Flat_packed_unsigneds.push_back(b);
26394 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26395  std::stringstream junk;
26396  junk << "Element associated to shared boundary " << b << " of " << nassociated_shared_boundaries << " total associated boundaries";
26397  Flat_packed_unsigneds_string.push_back(junk.str());
26398 #endif
26399 
26400  const unsigned f = face_index_on_shared_boundary[i];
26401  Flat_packed_unsigneds.push_back(f);
26402 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26403  std::stringstream junk2;
26404  junk2 << "Face index " << f << " for associated shared boundary " << b;
26405  Flat_packed_unsigneds_string.push_back(junk2.str());
26406 #endif
26407  }
26408  }
26409  else
26410  {
26411  Flat_packed_unsigneds.push_back(0);
26412 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26413  Flat_packed_unsigneds_string.push_back("The element is not associated to any shared boundary");
26414 #endif
26415  }
26416 
26417  // Now check if the element is haloed with any processor
26418 
26419  // Store the index of the haloed element with the jproc
26420  Vector<Vector<unsigned> > index_haloed(nproc);
26421 
26422  // Loop over the processors
26423  for (unsigned jproc = 0; jproc < nproc; jproc++)
26424  {
26425  // Get the number of haloed elements with jproc
26426  const unsigned n_haloed_jproc = f_haloed_ele_pt[jproc].size();
26427  // Loop over the haloed elements with jproc
26428  for (unsigned ihd =0; ihd < n_haloed_jproc; ihd++)
26429  {
26430  // Is a haloed element?
26431  if (ele_pt == f_haloed_ele_pt[jproc][ihd])
26432  {
26433  // Store the haloed index with the jproc processor
26434  index_haloed[jproc].push_back(ihd);
26435  // Break the searching with the jproc processor
26436  break;
26437  } // if (ele_pt == f_haloed_ele_pt[jproc][ihd])
26438 
26439  } // for (ihd < n_haloed_jproc)
26440 
26441  } // for (jproc < nproc)
26442 
26443  // Send the haloed info.
26444  // Loop over the processors
26445  for (unsigned jproc = 0; jproc < nproc; jproc++)
26446  {
26447  // Is the element haloed with the jproc processor
26448  const unsigned n_index_haloed_jproc = index_haloed[jproc].size();
26449  Flat_packed_unsigneds.push_back(n_index_haloed_jproc);
26450 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26451  Flat_packed_unsigneds_string.push_back("The number of haloed indexes the element is with processor jproc");
26452 #endif
26453  for (unsigned ihd = 0; ihd < n_index_haloed_jproc; ihd++)
26454  {
26455  Flat_packed_unsigneds.push_back(index_haloed[jproc][ihd]);
26456 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26457  Flat_packed_unsigneds_string.push_back("The haloed index of the element with jproc");
26458 #endif
26459  } // for (ihd < n_index_haloed_jproc)
26460 
26461  } // for (jproc < nproc)
26462 
26463  }
26464 
26465  //======================================================================
26466  /// \short Helper function to add nodes on a new domain as a result of
26467  /// load balance
26468  //======================================================================
26469  template <class ELEMENT>
26472  Vector<Vector<FiniteElement*> >&f_halo_ele_pt,
26473  Vector<Node*> &new_nodes_on_domain,
26474  Node* nod_pt)
26475  {
26476  // Attempt to add this node to the new domain
26477  const unsigned nnew_nodes_on_domain= new_nodes_on_domain.size();
26478  const unsigned new_added_node_index =
26479  this->try_to_add_node_pt_load_balance(new_nodes_on_domain, nod_pt);
26480 
26481  // If it was added then the new index should match the size of the storage
26482  if (new_added_node_index == nnew_nodes_on_domain)
26483  {
26484  Flat_packed_unsigneds.push_back(1);
26485 
26486 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26487  std::stringstream junk;
26488  junk << "Node needs to be constructed [size="
26489  << Flat_packed_unsigneds.size() << "]; last entry: "
26490  << Flat_packed_unsigneds[Flat_packed_unsigneds.size()-1];
26491  Flat_packed_unsigneds_string.push_back(junk.str());
26492 #endif
26493 
26494  // This helper function gets all the required information for the
26495  // specified node and stores it into MPI-sendable information
26496  // so that a new copy can be made on the receiving process
26497  get_required_nodal_information_load_balance_helper(f_halo_ele_pt,
26498  iproc,
26499  nod_pt);
26500  }
26501  else // It was already added
26502  {
26503  Flat_packed_unsigneds.push_back(0);
26504 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26505  std::stringstream junk;
26506  junk << "Node was already added [size="
26507  << Flat_packed_unsigneds.size() << "]; last entry: "
26508  << Flat_packed_unsigneds[Flat_packed_unsigneds.size()-1];
26509 
26510  Flat_packed_unsigneds_string.push_back(junk.str());
26511 #endif
26512 
26513  // This node has been already added, so tell the other process
26514  // its index in the equivalent storage
26515  Flat_packed_unsigneds.push_back(new_added_node_index);
26516 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26517  Flat_packed_unsigneds_string.push_back("new added node index");
26518 #endif
26519  }
26520 
26521  }
26522 
26523  //======start of get_required_nodal_information_load_balance_helper=======
26524  /// Helper function to get the required nodal information from an
26525  /// haloed node so that a fully-functional halo node (and therefore element)
26526  /// can be created on the receiving process
26527  //========================================================================
26528  template<class ELEMENT>
26531  Vector<Vector<FiniteElement*> > &f_halo_ele_pt,
26532  unsigned& iproc,
26533  Node* nod_pt)
26534  {
26535  unsigned my_rank = this->communicator_pt()->my_rank();
26536  const unsigned nproc = this->communicator_pt()->nproc();
26537 
26538  // Tell the halo copy of this node how many values there are
26539  // [NB this may be different for nodes within the same element, e.g.
26540  // when using Lagrange multipliers]
26541  unsigned n_val=nod_pt->nvalue();
26542  Flat_packed_unsigneds.push_back(n_val);
26543 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26544  Flat_packed_unsigneds_string.push_back("Number of values");
26545 #endif
26546 
26547  unsigned n_dim=nod_pt->ndim();
26548 
26549  // Default number of previous values to 1
26550  unsigned n_prev=1;
26551  if (this->Time_stepper_pt!=0)
26552  {
26553  // Add number of history values to n_prev
26554  n_prev=this->Time_stepper_pt->ntstorage();
26555  }
26556 
26557  // -----------------------------------------------------
26558  // Is the node on an original boundary?
26559  // Store the original boundaries where the node may be
26560  Vector<unsigned> original_boundaries;
26561  // Loop over the original boundaries of the mesh and check if live
26562  // on one of them
26563  const unsigned n_bnd = this->initial_shared_boundary_id();
26564  for (unsigned bb=0;bb<n_bnd;bb++)
26565  {
26566  // Which boundaries (could be more than one) is it on?
26567  if (nod_pt->is_on_boundary(bb))
26568  {
26569  original_boundaries.push_back(bb);
26570  }
26571 
26572  }
26573 
26574  const unsigned n_original_boundaries = original_boundaries.size();
26575  // Is the node on any original boundary?
26576  if (n_original_boundaries > 0)
26577  {
26578  // Indicate that the node is on an original boundary
26579  Flat_packed_unsigneds.push_back(2);
26580 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26581  Flat_packed_unsigneds_string.push_back("Node is on the original boundaries");
26582 #endif
26583 
26584  Flat_packed_unsigneds.push_back(n_original_boundaries);
26585 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26586  std::stringstream junk;
26587  junk << "Node is on "<< n_original_boundaries << " original boundaries";
26588  Flat_packed_unsigneds_string.push_back(junk.str());
26589 #endif
26590 
26591  // Loop over the original boundaries the node is on
26592  for (unsigned i=0;i<n_original_boundaries;i++)
26593  {
26594  Flat_packed_unsigneds.push_back(original_boundaries[i]);
26595 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26596  std::stringstream junk;
26597  junk<<"Node is on boundary "<<original_boundaries[i]<<" of "<< nb;
26598  Flat_packed_unsigneds_string.push_back(junk.str());
26599 #endif
26600  // Get the boundary coordinate of the node
26601  Vector<double> zeta(1);
26602  nod_pt->get_coordinates_on_boundary(original_boundaries[i],zeta);
26603  Flat_packed_doubles.push_back(zeta[0]);
26604  }
26605  }
26606  else
26607  {
26608  // Indicate that the node is NOT on an original boundary
26609  Flat_packed_unsigneds.push_back(0);
26610 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26611  Flat_packed_unsigneds_string.push_back("Node is on any original boundary");
26612 #endif
26613  }
26614 
26615  // -------------------------------------------------------
26616  // Is the node on shared boundaries?
26617  bool node_on_shared_boundary = false;
26618  // Loop over the shared boundaries with the iproc processors and
26619  // check if live on one of them
26620  const unsigned n_shd_bnd = this->nshared_boundaries(my_rank, iproc);
26621  for (unsigned bb=0;bb<n_shd_bnd;bb++)
26622  {
26623  // Get the boundary id
26624  unsigned i_bnd = this->shared_boundaries_ids(my_rank, iproc, bb);
26625  // Which boundaries (could be more than one) is it on?
26626  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
26627  {
26628  node_on_shared_boundary = true;
26629  break;
26630  }
26631  }
26632 
26633  // If the node live on any of the shared boundaries with the iproc
26634  // processor then just get the node number according to the
26635  // sorted_shared_boundary_node_pt() scheme and send it accross
26636  if (node_on_shared_boundary)
26637  {
26638  Flat_packed_unsigneds.push_back(1);
26639 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26640  Flat_packed_unsigneds_string.push_back("Node is on shared boundary");
26641 #endif
26642 
26643  // Store the shared boundaries where the node is on
26644  Vector<unsigned> shd_boundaries;
26645  // Loop over the shared boundaries with the iproc processor
26646  for (unsigned bb = 0; bb < n_shd_bnd; bb++)
26647  {
26648  // Get the boundary id
26649  const unsigned i_bnd =
26650  this->shared_boundaries_ids(my_rank, iproc, bb);
26651  // Which boundaries (could be more than one) is it on?
26652  if (this->is_node_on_shared_boundary(i_bnd, nod_pt))
26653  {
26654  shd_boundaries.push_back(i_bnd);
26655  }
26656  }
26657 
26658  // Get the number of shared boundaries the node is on
26659  const unsigned n_shd_bnd_is_on = shd_boundaries.size();
26660  // Send the number of shared boundaries the node is on
26661  Flat_packed_unsigneds.push_back(n_shd_bnd_is_on);
26662 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26663  std::stringstream junk;
26664  junk << "Node is on "<< n_shd_bnd_is_on << " shared boundaries";
26665  Flat_packed_unsigneds_string.push_back(junk.str());
26666 #endif
26667 
26668  // Loop over the shared boundaries to send their ids
26669  for (unsigned i=0;i<n_shd_bnd_is_on;i++)
26670  {
26671  Flat_packed_unsigneds.push_back(shd_boundaries[i]);
26672 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26673  std::stringstream junk;
26674  junk << "Node is on boundary " << shd_boundaries[i] << " of " << nb;
26675  Flat_packed_unsigneds_string.push_back(junk.str());
26676 #endif
26677  }
26678 
26679  // Given that the node is on at least one boundary get the index
26680  // of the node in one of the boundaries and send this index
26681  unsigned shared_boundary_id = shd_boundaries[0];
26682  // Get the number of nodes on the given shared boundary
26683  const unsigned n_nodes_on_shared_boundary =
26684  nsorted_shared_boundary_node(shared_boundary_id);
26685  // Store the index of the node on the shared boundary
26686  unsigned index_node_on_shared_boundary;
26687 #ifdef PARANOID
26688  // Flag to know if the node has been found
26689  bool found_index_node_on_shared_boundary = false;
26690 #endif
26691  // Loop over the nodes on the shared boundary to find the node
26692  for (unsigned i = 0; i < n_nodes_on_shared_boundary; i++)
26693  {
26694  // Get the i-th node on the shared boundary
26695  Node* shared_node_pt =
26696  sorted_shared_boundary_node_pt(shared_boundary_id, i);
26697  // Is the node we are looking for
26698  if (shared_node_pt == nod_pt)
26699  {
26700  // Store the index
26701  index_node_on_shared_boundary = i;
26702 #ifdef PARANOID
26703  // Mark as found
26704  found_index_node_on_shared_boundary = true;
26705 #endif
26706  break; // break
26707  }
26708 
26709  } // for (i < nnodes_on_shared_boundary)
26710 
26711 #ifdef PARANOID
26712  if (!found_index_node_on_shared_boundary)
26713  {
26714  std::ostringstream error_message;
26715  error_message
26716  <<"The index of the node on boundary ("
26717  <<shared_boundary_id<<") was not found.\n"
26718  <<"The node coordinates are ("<<nod_pt->x(0)<<","
26719  <<nod_pt->x(1)<<").\n";
26720  throw OomphLibError(
26721  error_message.str(),
26722  "RefineableTriangleMesh::get_required_nodal_information_helper()",
26723  OOMPH_EXCEPTION_LOCATION);
26724  }
26725 #endif
26726  // Send the index of the node on the shared boundary
26727  Flat_packed_unsigneds.push_back(index_node_on_shared_boundary);
26728 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26729  std::stringstream junk2;
26730  junk2 << "Node index on boundary "<<boundaries[0]<<" is "
26731  <<index_node_on_shared_boundary;
26732  Flat_packed_unsigneds_string.push_back(junk2.str());
26733 #endif
26734 
26735  } // if (node_on_shared_boundary)
26736  else
26737  {
26738  // The node is not on a shared boundary
26739  Flat_packed_unsigneds.push_back(0);
26740 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26741  Flat_packed_unsigneds_string.push_back("Node is not on a shared boundary");
26742 #endif
26743  }
26744 
26745  // ----------------------------------------------------------------
26746  // Is the node on any shared boundary where the receiver processor
26747  // is not involved?
26748 
26749  // Now check if the node is on a shared boundary created by the
26750  // current processor (my_rank) and other processor different that
26751  // the iproc processor. This info. will help to complete the sending
26752  // of halo(ed) information between processors
26753 
26754  // Flag to know if the node is on a shared boundary with other
26755  // processor
26756  bool node_on_shared_boundary_with_other_processors = false;
26757  // Count the number of other shared boundaries it could be on
26758  unsigned nshared_boundaries_with_other_processors_have_node = 0;
26759 
26760  // Loop over the shared boundaries of the sent processor (my_rank)
26761  // and other processors (jproc)
26762  for (unsigned jproc = 0; jproc < nproc; jproc++)
26763  {
26764  // Do not search with the iproc processor, that was done before
26765  // above
26766  if (jproc != iproc)
26767  {
26768  // Get the number of shared boundaries with the jproc processor
26769  const unsigned n_jshd_bnd =
26770  this->nshared_boundaries(my_rank, jproc);
26771  // Loop over the shared boundaries
26772  for (unsigned bb=0;bb<n_jshd_bnd;bb++)
26773  {
26774  // Get the boundary id
26775  const unsigned j_shd_bnd =
26776  this->shared_boundaries_ids(my_rank, jproc, bb);
26777  // Is the node part of this boundary?
26778  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
26779  {
26780 // DEBP("Sending to");
26781 // DEBP(iproc);
26782 // DEBP("Pair of procs where other shared");
26783 // DEBP(my_rank);
26784 // DEBP(jproc);
26785 // DEBP(i_bnd);
26786  node_on_shared_boundary_with_other_processors = true;
26787  // Increase the counter for the number of shared boundaries
26788  // with other processors the node is on
26789  nshared_boundaries_with_other_processors_have_node++;
26790  } // if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt)
26791 
26792  } // for (bb<n_jshd_bnd)
26793 
26794  } // if (jproc != iproc)
26795 
26796  } // for (jproc < nproc)
26797 
26798  // If the node is on a shared boundary with another processor
26799  // (my_rank, jproc), then send the flag and look for the info.
26800  if (node_on_shared_boundary_with_other_processors)
26801  {
26802  Flat_packed_unsigneds.push_back(4);
26803 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26804  Flat_packed_unsigneds_string.push_back("Node is on shared boundary no related with the received processor: 4");
26805 #endif
26806 
26807  // The number of packages of information that will be sent to the
26808  // "iproc" processor. This helps to know how many packages of data
26809  // read from the received processor
26810  Flat_packed_unsigneds.push_back(nshared_boundaries_with_other_processors_have_node);
26811 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26812  std::stringstream junk;
26813  junk << "Number of other shared boundaries that the node is on: "
26814  << nshared_boundaries_with_other_processors_have_node;
26815  Flat_packed_unsigneds_string.push_back(junk.str());
26816 #endif
26817 
26818  // Counter to ensure that the correct number of data has been sent
26819  unsigned counter_shd_bnd_with_other_procs_have_node = 0;
26820  // Loop over the shared boundaries with other processors and get:
26821  // 1) The processors defining the shared boundary
26822  // 2) The shared boundary id
26823  // 3) The index of the node on the shared boundary
26824  Vector<unsigned> other_processor_1;
26825  Vector<unsigned> other_processor_2;
26826  Vector<unsigned> shd_bnd_ids;
26827  Vector<unsigned> indexes;
26828  // Loop over the processors again
26829  for (unsigned jproc = 0; jproc < nproc; jproc++)
26830  {
26831  // Do not search with the iproc processor, that was done before
26832  // above
26833  if (jproc != iproc)
26834  {
26835  // Get the number of shared boundaries with the jproc
26836  // processor
26837  const unsigned n_jshd_bnd =
26838  this->nshared_boundaries(my_rank, jproc);
26839  for (unsigned bb = 0; bb < n_jshd_bnd; bb++)
26840  {
26841  // Get the boundary id
26842  const unsigned j_shd_bnd =
26843  this->shared_boundaries_ids(my_rank, jproc, bb);
26844  // Is the node part of this boundary?
26845  if (this->is_node_on_shared_boundary(j_shd_bnd, nod_pt))
26846  {
26847  // Include the first processor
26848  other_processor_1.push_back(my_rank);
26849  // Include the second processor
26850  other_processor_2.push_back(jproc);
26851  // Include the shared boundary id
26852  shd_bnd_ids.push_back(j_shd_bnd);
26853  // Increase the counter for found shared boundaries with
26854  // other processors
26855  counter_shd_bnd_with_other_procs_have_node++;
26856  }
26857 
26858  } // for (bb < nshared_bnd)
26859 
26860  } // if (jproc != iproc)
26861 
26862  } // for (jproc < nproc)
26863 
26864  // Get the indexes of the node on all the shared boundaries where
26865  // it was found
26866  const unsigned n_other_processors = other_processor_1.size();
26867  // Loop over the processors where the node was found
26868  for (unsigned i = 0; i < n_other_processors; i++)
26869  {
26870  // Get the shared boundary id
26871  unsigned shd_bnd_id = shd_bnd_ids[i];
26872  // Get the number of nodes on that shared boundary
26873  const unsigned n_nodes_on_shd_bnd =
26874  nsorted_shared_boundary_node(shd_bnd_id);
26875 
26876 #ifdef PARANOID
26877  bool found_index_node_on_shared_boundary = false;
26878 #endif
26879  for (unsigned i = 0; i < n_nodes_on_shd_bnd; i++)
26880  {
26881  // Get the i-th shared boundary node
26882  Node* shared_node_pt =
26883  sorted_shared_boundary_node_pt(shd_bnd_id, i);
26884  // Is the same node?
26885  if (shared_node_pt == nod_pt)
26886  {
26887 // DEBP(i_node);
26888 // DEBP(nod_pt->x(0));
26889 // DEBP(nod_pt->x(1));
26890  // Include the index of the node
26891  indexes.push_back(i);
26892 #ifdef PARANOID
26893  // Mark as found the node
26894  found_index_node_on_shared_boundary = true;
26895 #endif
26896  break;
26897  } // if (shared_node_pt == nod_pt)
26898 
26899  } // for (i < n_nodes_on_shd_bnd)
26900 
26901 #ifdef PARANOID
26902  if (!found_index_node_on_shared_boundary)
26903  {
26904  std::ostringstream error_message;
26905  error_message
26906  <<"The index of the node on boundary ("
26907  <<shd_bnd_id<<"), shared by other processors\nwas not found.\n"
26908  <<"The node coordinates are ("<<nod_pt->x(0)<<","
26909  <<nod_pt->x(1)<<").\n";
26910  throw OomphLibError(
26911  error_message.str(),
26912  "RefineableTriangleMesh::get_required_nodal_information_helper()",
26913  OOMPH_EXCEPTION_LOCATION);
26914  }
26915 #endif
26916  } // for (i < n_other_processors)
26917 
26918  // Now send the info. but first check that the number of found
26919  // nodes be the same that the previously found shared boundaries
26920  // with the node
26921 #ifdef PARANOID
26922  if (counter_shd_bnd_with_other_procs_have_node !=
26923  nshared_boundaries_with_other_processors_have_node)
26924  {
26925  std::ostringstream error_message;
26926  error_message
26927  <<"The number of shared boundaries where the node is on "
26928  <<"is different:\n"
26929  << "nshared_boundaries_with_other_processors_have_node: ("
26930  << nshared_boundaries_with_other_processors_have_node
26931  << ")\n"
26932  << "counter_shd_bnd_with_other_procs_have_node: ("
26933  << counter_shd_bnd_with_other_procs_have_node
26934  << ")\n";
26935  throw OomphLibError(
26936  error_message.str(),
26937  "RefineableTriangleMesh::get_required_nodal_information_helper()",
26938  OOMPH_EXCEPTION_LOCATION);
26939  } // if (counter_shd_bnd_with_other_procs_have_node !=
26940  // nshared_boundaries_with_other_processors_have_node)
26941 #endif
26942 
26943  // Loop over the info. to send it
26944  for (unsigned i = 0; i < n_other_processors; i++)
26945  {
26946  Flat_packed_unsigneds.push_back(other_processor_1[i]);
26947 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26948  std::stringstream junk1;
26949  junk1 << "Processor where the other shared boundary "
26950  << "has the node: " << other_processor_1[i];
26951  Flat_packed_unsigneds_string.push_back(junk1.str());
26952 #endif
26953 
26954  Flat_packed_unsigneds.push_back(other_processor_2[i]);
26955 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26956  std::stringstream junk2;
26957  junk2 << "Processor where the other shared boundary "
26958  << "has the node: " << other_processor_2[i];
26959  Flat_packed_unsigneds_string.push_back(junk2.str());
26960 #endif
26961 
26962  Flat_packed_unsigneds.push_back(shd_bnd_ids[i]);
26963 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26964  std::stringstream junk3;
26965  junk3 << "Other shared boundary id where the node is on"
26966  << boundaries[i];
26967  Flat_packed_unsigneds_string.push_back(junk3.str());
26968 #endif
26969 
26970  Flat_packed_unsigneds.push_back(indexes[i]);
26971 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26972  std::stringstream junk4;
26973  junk4 << "Node index on other shared boundary "
26974  <<boundaries[i] << " is "
26975  << indexes[i];
26976  Flat_packed_unsigneds_string.push_back(junk4.str());
26977 #endif
26978 
26979  } // for (i < n_other_processors)
26980 
26981  } // if (node_on_shared_boundary_with_other_processors)
26982  else
26983  {
26984  Flat_packed_unsigneds.push_back(0);
26985 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
26986  Flat_packed_unsigneds_string.push_back("Node is on any shared boundary with other processors");
26987 #endif
26988  } // else if (node_on_shared_boundary_with_other_processors)
26989 
26990  // It may still be possible that the node be shared with the
26991  // processor that receives the info. but it is neither on shared
26992  // boundary with the receiver processor nor on a shared boundary
26993  // with others processors. Think in the next case:
26994 
26995  // |-----|-----| - The elements in processor 3 need to be sent to
26996  // | 4 | 3 | processor 1, and that is all
26997  // |-----*-----| - When processor 1 receives the data from node (*)
26998  // | 1 | 2 | it just RE-CREATES it becasuse it is does not know
26999  // |-----|-----| that the node is also on the shared boundary that
27000  // processor 1 and 2 or processor 1 and 4 share.
27001 
27002  // This problem become even worse if there would be more processors
27003  // between processor 3 and 2, or/and processor 3 and 4. Think in
27004  // triangles sharing the node (*)
27005 
27006  // To solve this check if the node that we are trying to send is
27007  // part of the halo elements of the curreent processor (my_rank)
27008  // with any other processor (we need to check with all the
27009  // processors and not just with the processors to which we will send
27010  // to cover more cases)
27011 
27012  // Store the halo element number with jproc where the node was found
27013  Vector<Vector<unsigned> > halo_element_number(nproc);
27014  // Store the node number on the halo element where the node was found
27015  Vector<Vector<unsigned> > halo_node_number_in_halo_element(nproc);
27016 
27017  // Loop over the processor
27018  for (unsigned jproc = 0; jproc < nproc; jproc++)
27019  {
27020  // Get the number of halo elements with the jproc processor
27021  const unsigned n_halo_jproc = f_halo_ele_pt[jproc].size();
27022  // Loop over the halo elements
27023  for (unsigned jh = 0; jh < n_halo_jproc; jh++)
27024  {
27025  FiniteElement* halo_ele_pt = f_halo_ele_pt[jproc][jh];
27026  // Get the number of nodes of the halo element
27027  const unsigned n_node = halo_ele_pt->nnode();
27028  // Loop over the nodes
27029  for (unsigned n = 0; n < n_node; n++)
27030  {
27031  // Is the node part of the ih-th halo element with jproc
27032  if (nod_pt == halo_ele_pt->node_pt(n))
27033  {
27034  halo_element_number[jproc].push_back(jh);
27035  halo_node_number_in_halo_element[jproc].push_back(n);
27036  // break with the nodes, no need to look for more nodes in
27037  // the element
27038  break;
27039  } // if (nod_pt == halo_ele_pt->node_pt(n))
27040 
27041  } // for (n < n_node)
27042 
27043  } // for (jh < n_halo_jproc)
27044 
27045  } // for (jproc < nproc)
27046 
27047  // Send the info. related with if the node is on halo elements with
27048  // any processor
27049 
27050  // Loop over the processors
27051  for (unsigned jproc = 0; jproc < nproc; jproc++)
27052  {
27053  // Get the number of halo elements with jproc processor where the
27054  // node is
27055  const unsigned n_jproc_halo_ele_node_is_on =
27056  halo_element_number[jproc].size();
27057  // Send the number of halo elements with jproc where the node is
27058  Flat_packed_unsigneds.push_back(n_jproc_halo_ele_node_is_on);
27059 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27060  std::stringstream junk5;
27061  junk5 << "Node is on " << n_jproc_halo_ele_node_is_on << " halo "
27062  << "elements with " << jproc << "-th processor";
27063  Flat_packed_unsigneds_string.push_back(junk5.str());
27064 #endif
27065  // Send the halo elements indexes (which will be haloed elements
27066  // indexes in the receiver processor), and the indexes of the
27067  // nodes in each halo element
27068  for (unsigned i = 0; i < n_jproc_halo_ele_node_is_on; i++)
27069  {
27070  // The halo element index
27071  const unsigned halo_element_index = halo_element_number[jproc][i];
27072  Flat_packed_unsigneds.push_back(halo_element_index);
27073 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27074  std::stringstream junk6;
27075  junk6 << "Halo element index is ("<<halo_element_index
27076  <<") with processor ("<<jproc<<")";
27077  Flat_packed_unsigneds_string.push_back(junk6.str());
27078 #endif
27079  // The node index on the halo element
27080  const unsigned node_index = halo_node_number_in_halo_element[jproc][i];
27081  Flat_packed_unsigneds.push_back(node_index);
27082 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27083  std::stringstream junk7;
27084  junk7 << "The node index on the halo element index is ("
27085  << node_index;
27086  Flat_packed_unsigneds_string.push_back(junk7.str());
27087 #endif
27088 
27089  } // for (i < n_jproc_halo_ele_node_is_on)
27090 
27091  } // for (jproc < nproc)
27092 
27093  // Now check if it is required to send the info. of the node. If the
27094  // node is not on a shared boundary with the iproc processor then we
27095  // need to send the info.
27096 
27097  // Flag to indicate if it is on a halo element with the iproc
27098  // processor. If this flag is true then there is no need to send the
27099  // info. to create the node, in the receiver processor the info is
27100  // copied from the indicated haloed element-node
27101  bool on_halo_element_with_iproc_processor = false;
27102  if (halo_element_number[iproc].size() > 0)
27103  {
27104  on_halo_element_with_iproc_processor = true;
27105  } // if (halo_element_number[iproc].size() > 0)
27106 
27107  // if (!node_on_shared_boundary)
27108  if (!node_on_shared_boundary && !on_halo_element_with_iproc_processor)
27109  {
27110  // Send all the info. to create it
27111 
27112  // Is the Node algebraic? If so, send its ref values and
27113  // an indication of its geometric objects if they are stored
27114  // in the algebraic mesh
27115  AlgebraicNode* alg_nod_pt=dynamic_cast<AlgebraicNode*>(nod_pt);
27116  if (alg_nod_pt!=0)
27117  {
27118  // The external mesh should be algebraic
27119  AlgebraicMesh* alg_mesh_pt=dynamic_cast<AlgebraicMesh*>(this);
27120 
27121  // Get default node update function ID
27122  unsigned update_id=alg_nod_pt->node_update_fct_id();
27123  Flat_packed_unsigneds.push_back(update_id);
27124 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27125  Flat_packed_unsigneds_string.push_back("Alg Node update id");
27126 #endif
27127 
27128  // Get reference values at default...
27129  unsigned n_ref_val=alg_nod_pt->nref_value();
27130  Flat_packed_unsigneds.push_back(n_ref_val);
27131 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27132  Flat_packed_unsigneds_string.push_back("Alg Node n ref values");
27133 #endif
27134  for (unsigned i_ref_val=0;i_ref_val<n_ref_val;i_ref_val++)
27135  {
27136  Flat_packed_doubles.push_back(alg_nod_pt->ref_value(i_ref_val));
27137  }
27138 
27139  // Access geometric objects at default...
27140  unsigned n_geom_obj=alg_nod_pt->ngeom_object();
27141  Flat_packed_unsigneds.push_back(n_geom_obj);
27142 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27143  Flat_packed_unsigneds_string.push_back("Alg Node n geom objects");
27144 #endif
27145  for (unsigned i_geom=0;i_geom<n_geom_obj;i_geom++)
27146  {
27147  GeomObject* geom_obj_pt=alg_nod_pt->geom_object_pt(i_geom);
27148 
27149  // Check this against the stored geometric objects in mesh
27150  unsigned n_geom_list=alg_mesh_pt->ngeom_object_list_pt();
27151 
27152  // Default found index to zero
27153  unsigned found_geom_object=0;
27154  for (unsigned i_list=0;i_list<n_geom_list;i_list++)
27155  {
27156  if (geom_obj_pt==alg_mesh_pt->geom_object_list_pt(i_list))
27157  {
27158  found_geom_object=i_list;
27159  }
27160  }
27161  Flat_packed_unsigneds.push_back(found_geom_object);
27162 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27163  Flat_packed_unsigneds_string.push_back("Found geom object");
27164 #endif
27165  }
27166  } // (if alg_nod_pt!=0)
27167 
27168  // Is it a SolidNode?
27169  SolidNode* solid_nod_pt=dynamic_cast<SolidNode*>(nod_pt);
27170  if (solid_nod_pt!=0)
27171  {
27172  unsigned n_solid_val=solid_nod_pt->variable_position_pt()->nvalue();
27173  for (unsigned i_val=0;i_val<n_solid_val;i_val++)
27174  {
27175  for (unsigned t=0;t<n_prev;t++)
27176  {
27177  Flat_packed_doubles.push_back(solid_nod_pt->variable_position_pt()->
27178  value(t,i_val));
27179  }
27180  }
27181 
27182  Vector<double> values_solid_node;
27183  solid_nod_pt->add_values_to_vector(values_solid_node);
27184  const unsigned nvalues_solid_node = values_solid_node.size();
27185  Flat_packed_unsigneds.push_back(nvalues_solid_node);
27186 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27187  std::stringstream junk;
27188  junk << "Number of values solid node: "
27189  << nvalues_solid_node;
27190  Flat_packed_unsigneds_string.push_back(junk.str());
27191 #endif
27192  for (unsigned i = 0; i < nvalues_solid_node; i++)
27193  {
27194  Flat_packed_doubles.push_back(values_solid_node[i]);
27195  }
27196  }
27197 
27198  // Finally copy info required for all node types
27199  for (unsigned i_val=0;i_val<n_val;i_val++)
27200  {
27201  for (unsigned t=0;t<n_prev;t++)
27202  {
27203  Flat_packed_doubles.push_back(nod_pt->value(t,i_val));
27204  }
27205  }
27206 
27207  // Now do positions
27208  for (unsigned idim=0;idim<n_dim;idim++)
27209  {
27210  for (unsigned t=0;t<n_prev;t++)
27211  {
27212  Flat_packed_doubles.push_back(nod_pt->x(t,idim));
27213 // DEBP(nod_pt->x(t,idim));
27214  }
27215  }
27216 
27217  } // if (!node_on_shared_boundary && !on_halo_element_with_iproc_processor)
27218 
27219  }
27220 
27221  //======================================================================
27222  /// \short Helper function to create elements on the loop
27223  /// process based on the info received in
27224  /// send_and_received_elements_nodes_info
27225  //======================================================================
27226  template <class ELEMENT>
27228  unsigned& iproc,
27229  Vector<Vector<FiniteElement*> > &f_haloed_ele_pt,
27230  Vector<Vector<std::map<unsigned,FiniteElement*> > >
27231  &received_old_haloed_element_pt,
27232  Vector<FiniteElement*> &new_elements_on_domain,
27233  Vector<Node*> &new_nodes_on_domain,
27234  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
27235  &other_proc_shd_bnd_node_pt,
27236  Vector<Vector<Vector<unsigned> > > &global_node_names,
27237  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
27238  Vector<Node*> &global_shared_node_pt)
27239  {
27240 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27241  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27242  << " Bool: New element needs to be constructed "
27243  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27244  << std::endl;
27245 #endif
27246 
27247  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]==1)
27248  {
27249  // Create a new element from the communicated values
27250  // and coords from the process that located zeta
27251  GeneralisedElement *new_el_pt= new ELEMENT;
27252 
27253  // Add the new element to the mesh - Do not add the element yet
27254  // since no retained elements still need to be deleted
27255  // this->add_element_pt(new_el_pt);
27256 
27257  // Cast to the FE pointer
27258  FiniteElement* f_el_pt=dynamic_cast<FiniteElement*>(new_el_pt);
27259 
27260  // Add the element to the new elements in the domain container
27261  new_elements_on_domain.push_back(f_el_pt);
27262 
27263  // Set any additional information for the element
27264  this->add_element_load_balance_helper(iproc,
27265  received_old_haloed_element_pt,
27266  f_el_pt);
27267 
27268  // Add nodes to the new element
27269  unsigned n_node=f_el_pt->nnode();
27270  for (unsigned j=0;j<n_node;j++)
27271  {
27272  Node* new_nod_pt=0;
27273 
27274  // Call the add halo node helper function
27275  add_received_node_load_balance_helper(new_nod_pt,
27276  f_haloed_ele_pt,
27277  received_old_haloed_element_pt,
27278  new_nodes_on_domain,
27279  other_proc_shd_bnd_node_pt,
27280  iproc, j, f_el_pt,
27281  global_node_names,
27282  node_name_to_global_index,
27283  global_shared_node_pt);
27284  }
27285  }
27286  else // the element already exists
27287  {
27288 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27289  oomph_info
27290  << "Rec:" << Counter_for_flat_packed_unsigneds
27291  << " Index of existing element "
27292  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27293  << std::endl;
27294 #endif
27295 
27296  // Incrase the index, we do anything else with the element
27297  Counter_for_flat_packed_unsigneds++;
27298 
27299  } // else the element already exists
27300 
27301  }
27302 
27303  //========start of add_element_load_balance_helper=====================
27304  /// \short Helper function to create elements on the loop
27305  /// process based on the info received in
27306  /// send_and_received_elements_nodes_info
27307  /// This function is in charge of verify if the element is associated
27308  /// to a boundary and associate to it if that is the case
27309  //======================================================================
27310  template<class ELEMENT>
27312  add_element_load_balance_helper(const unsigned &iproc,
27313  Vector<Vector<std::map<
27314  unsigned,FiniteElement*> > >
27315  &received_old_haloed_element_pt,
27316  FiniteElement* ele_pt)
27317  {
27318  // Get the number of processors
27319  const unsigned nproc = this->communicator_pt()->nproc();
27320 
27321 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27322  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27323  << " Bool: Element is associated to a boundary "
27324  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27325  << std::endl;
27326 #endif
27327 
27328  // Is on an original boundary?
27329  const unsigned is_on_original_boundary =
27330  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27331  if (is_on_original_boundary == 1)
27332  {
27333 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27334  oomph_info
27335  << "Rec:" << Counter_for_flat_packed_unsigneds
27336  << " How many boundaries are associated with the element "
27337  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27338  << std::endl;
27339 #endif
27340  // Number of boundaries the element is associated with
27341  const unsigned nassociated_boundaries =
27342  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27343 
27344  // Loop over the associated boundaries
27345  for (unsigned b = 0; b < nassociated_boundaries; b++)
27346  {
27347 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27348  oomph_info
27349  << "Rec:" << Counter_for_flat_packed_unsigneds
27350  << " Boundary associated to the element "
27351  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27352  << std::endl;
27353 #endif
27354 
27355  // The boundary id
27356  const unsigned bnd =
27357  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27358 
27359 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27360  oomph_info
27361  << "Rec:" << Counter_for_flat_packed_unsigneds
27362  << " Face index of the element "
27363  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27364  << std::endl;
27365 #endif
27366 
27367  // The face index
27368  const unsigned face_index =
27369  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27370 
27371  // Associate the element with the boundary and establish as many
27372  // face indexes it has
27373  this->Boundary_element_pt[bnd].push_back(ele_pt);
27374  this->Face_index_at_boundary[bnd].push_back(face_index);
27375 
27376  } // (b < nassociated_boundaries)
27377 
27378  // Here read the info. regarding the boundary-region of the element
27379 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27380  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27381  << " Bool: Element is associated to a boundary-region "
27382  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27383  << std::endl;
27384 #endif
27385 
27386  // Is the element associated to a boundary-region?
27387  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]==1)
27388  {
27389 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27390  oomph_info
27391  << "Rec:" << Counter_for_flat_packed_unsigneds
27392  << " How many boundaries-regions are associated with the element "
27393  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27394  << std::endl;
27395 #endif
27396  // Number of boundary-regions the element is associated
27397  const unsigned nassociated_boundaries_and_regions =
27398  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27399 
27400  for (unsigned br = 0; br < nassociated_boundaries_and_regions; br++)
27401  {
27402 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27403  oomph_info
27404  << "Rec:" << Counter_for_flat_packed_unsigneds
27405  << " Boundary associated to the element "
27406  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27407  << std::endl;
27408 #endif
27409  // The boundary id
27410  const unsigned bnd =
27411  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27412 
27413 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27414  oomph_info
27415  << "Rec:" << Counter_for_flat_packed_unsigneds
27416  << " Region associated to the element "
27417  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27418  << std::endl;
27419 #endif
27420  // The region id
27421  const unsigned region =
27422  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27423 
27424 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27425  oomph_info
27426  << "Rec:" << Counter_for_flat_packed_unsigneds
27427  << " Face index of the element in boundary-region "
27428  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27429  << std::endl;
27430 #endif
27431  const unsigned face_index =
27432  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27433 
27434  // Associate the element with the boundary-regions and establish
27435  // as many face indexes it has
27436  this->Boundary_region_element_pt[bnd][region].push_back(ele_pt);
27437  this->Face_index_region_at_boundary[bnd][region].push_back(face_index);
27438 
27439  } // for (br < nassociated_boundaries_and_regions)
27440 
27441  } // Is the element associated with a boundary-region?
27442 
27443  } // The element is associated with an original boundary
27444 #ifdef PARANOID
27445  else
27446  {
27447  if (is_on_original_boundary != 0)
27448  {
27449  std::ostringstream error_message;
27450  error_message
27451  <<"The current element is not on an original boundary, this should\n"
27452  <<"be indicated by a zero flag. However, the read value for\n"
27453  <<"that flag is ("<<is_on_original_boundary<<").\n\n";
27454  throw OomphLibError(
27455  error_message.str(),
27456  "RefineableTriangleMesh::add_element_load_balance_helper()",
27457  OOMPH_EXCEPTION_LOCATION);
27458  } // if (is_on_shared_boundary != 0)
27459  }
27460 #endif
27461 
27462 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27463  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27464  << " Bool: Element is associated to a shared boundary "
27465  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27466  << std::endl;
27467 #endif
27468 
27469  // Is the element a shared boundary element?
27470  const unsigned is_on_shared_boundary =
27471  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27472  if (is_on_shared_boundary == 3)
27473  {
27474 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27475  oomph_info
27476  << "Rec:" << Counter_for_flat_packed_unsigneds
27477  << " How many shared boundaries are associated with the element "
27478  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27479  << std::endl;
27480 #endif
27481 
27482  // The number of shared boundaries the element is associated
27483  const unsigned nassociated_shared_boundaries =
27484  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27485 
27486  // Loop over the associated shared boundaries
27487  for (unsigned b = 0; b < nassociated_shared_boundaries; b++)
27488  {
27489 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27490  oomph_info
27491  << "Rec:" << Counter_for_flat_packed_unsigneds
27492  << " Shared boundary associated to the element "
27493  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27494  << std::endl;
27495 #endif
27496  const unsigned bnd =
27497  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27498 
27499 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27500  oomph_info
27501  << "Rec:" << Counter_for_flat_packed_unsigneds
27502  << " Face index of the element associated to the shared boundary "
27503  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27504  << std::endl;
27505 #endif
27506 
27507  const unsigned face_index =
27508  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27509 
27510  this->add_shared_boundary_element(bnd, ele_pt);
27511  this->add_face_index_at_shared_boundary(bnd, face_index);
27512 
27513  } // (b < nassociated_shared_boundaries)
27514 
27515  } // The element is associted with a shared boundary
27516 #ifdef PARANOID
27517  else
27518  {
27519  if (is_on_shared_boundary != 0)
27520  {
27521  std::ostringstream error_message;
27522  error_message
27523  <<"The current element is not on a shared boundary, this should\n"
27524  <<"be indicated by a zero flag. However, the read value for\n"
27525  <<"that flag is ("<<is_on_shared_boundary<<").\n\n";
27526  throw OomphLibError(
27527  error_message.str(),
27528  "RefineableTriangleMesh::add_element_load_balance_helper()",
27529  OOMPH_EXCEPTION_LOCATION);
27530  } // if (is_on_shared_boundary != 0)
27531  }
27532 #endif
27533 
27534  // Now check if the element is a haloed element in the sender
27535  // processor with any other processor
27536 
27537  // Loop over the processors
27538  for (unsigned jproc = 0; jproc < nproc; jproc++)
27539  {
27540 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27541  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27542  << " Bool: Number of haloed indexes of the element with the "
27543  << jproc << " processor: "
27544  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27545  << std::endl;
27546 #endif
27547  // Is the element haloed with the jproc processor
27548  const unsigned n_index_haloed_jproc =
27549  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27550  // Loop over the number of haloed indexes
27551  for (unsigned ihd = 0; ihd < n_index_haloed_jproc; ihd++)
27552  {
27553 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27554  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27555  << " Bool: The haloed element index with the "
27556  << jproc << " processor: "
27557  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27558  << std::endl;
27559 #endif
27560  const unsigned haloed_index =
27561  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27562 
27563  // Set the halod element in the proper storage
27564  received_old_haloed_element_pt[iproc][jproc][haloed_index] = ele_pt;
27565 
27566  } // for (ihd < n_index_haloed_jproc)
27567 
27568  } // for (jproc < nproc)
27569 
27570  }
27571 
27572  //======================================================================
27573  /// \short Helper function to add a new node from load balance
27574  //======================================================================
27575  template <class ELEMENT>
27578  Vector<Vector<FiniteElement*> >
27579  &f_haloed_ele_pt,
27580  Vector<Vector<std::map<
27581  unsigned,FiniteElement*> > >
27582  &received_old_haloed_element_pt,
27583  Vector<Node*> &new_nodes_on_domain,
27584  Vector<Vector<Vector<
27585  std::map<unsigned, Node*> > > >
27586  &other_proc_shd_bnd_node_pt,
27587  unsigned& iproc,
27588  unsigned& node_index,
27589  FiniteElement* const &new_el_pt,
27590  Vector<Vector<Vector<unsigned> > >
27591  &global_node_names,
27592  std::map<Vector<unsigned>, unsigned>
27593  &node_name_to_global_index,
27594  Vector<Node*> &global_shared_node_pt)
27595  {
27596  // Given the node, received information about it from processor
27597  // iproc, construct it on the current process
27598 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27599  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27600  << " Bool: New node needs to be constructed "
27601  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27602  << std::endl;
27603 #endif
27604  if (Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]==1)
27605  {
27606  // Construct a new node based upon sent information, or copy a node
27607  // from one of the shared boundaries
27608  construct_new_node_load_balance_helper(new_nod_pt,
27609  f_haloed_ele_pt,
27610  received_old_haloed_element_pt,
27611  new_nodes_on_domain,
27612  other_proc_shd_bnd_node_pt,
27613  iproc,
27614  node_index,
27615  new_el_pt,
27616  global_node_names,
27617  node_name_to_global_index,
27618  global_shared_node_pt);
27619  }
27620  else
27621  {
27622 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27623  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27624  << " Index of existing halo node "
27625  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27626  << std::endl;
27627 #endif
27628  // The node already exist, copy it from the indicated position
27629 
27630  // Get the node's index, and copy it
27631  new_nod_pt = new_nodes_on_domain[
27632  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++]];
27633 
27634  // Set the node in the current element
27635  new_el_pt->node_pt(node_index) = new_nod_pt;
27636 
27637  }
27638 
27639  }
27640 
27641  //============start_of_construct_new_node_load_balance_helper()=========
27642  /// \short Helper function which constructs a new node (on an
27643  /// element) with the information sent from the load balance
27644  /// process
27645  //======================================================================
27646  template<class ELEMENT>
27649  Node* &new_nod_pt,
27650  Vector<Vector<FiniteElement*> > &f_haloed_ele_pt,
27651  Vector<Vector<std::map<unsigned,FiniteElement*> > >
27652  &received_old_haloed_element_pt,
27653  Vector<Node*> &new_nodes_on_domain,
27654  Vector<Vector<Vector<std::map<unsigned, Node*> > > >
27655  &other_proc_shd_bnd_node_pt,
27656  unsigned& iproc, unsigned& node_index,
27657  FiniteElement* const &new_el_pt,
27658  Vector<Vector<Vector<unsigned> > > &global_node_names,
27659  std::map<Vector<unsigned>, unsigned> &node_name_to_global_index,
27660  Vector<Node*> &global_shared_node_pt)
27661  {
27662  // Get the number of processors
27663  const unsigned nproc = this->communicator_pt()->nproc();
27664  // Get the rank of the current processor
27665  const unsigned my_rank = this->communicator_pt()->my_rank();
27666 
27667  //The first entry indicates the number of values at this new Node
27668  //(which may be different across the same element e.g. Lagrange multipliers)
27669 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27670  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27671  << " Number of values of external halo node "
27672  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27673  << std::endl;
27674 #endif
27675  unsigned n_val=Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27676 
27677  // Null TimeStepper for now
27678  TimeStepper* time_stepper_pt=this->Time_stepper_pt;
27679  // Default number of previous values to 1
27680  unsigned n_prev=time_stepper_pt->ntstorage();
27681 
27682  // ------------------------------------------------------
27683  // Check if the node is on an original boundary
27684 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27685  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27686  << " Is the node on an original boundary "
27687  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27688  << std::endl;
27689 #endif
27690 
27691  // Flag to indicate if the node is on original boundaries
27692  const unsigned node_on_original_boundaries =
27693  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27694 
27695  // Store the original boundaries where the node is on
27696  Vector<unsigned> original_boundaries_node_is_on;
27697  // Store the zeta coordinates of the node on the original boundaries
27698  Vector<double> zeta_coordinates;
27699  // Store the number of original boundaries the node is on
27700  unsigned n_original_boundaries_node_is_on = 0;
27701 
27702  if (node_on_original_boundaries==2)
27703  {
27704  // How many original boundaries does the node live on?
27705 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27706  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27707  << " Number of boundaries the node is on: "
27708  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27709  << std::endl;
27710 #endif
27711  n_original_boundaries_node_is_on =
27712  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27713 
27714  // Resize the containers
27715  original_boundaries_node_is_on.resize(n_original_boundaries_node_is_on);
27716  zeta_coordinates.resize(n_original_boundaries_node_is_on);
27717 
27718  for (unsigned i=0;i<n_original_boundaries_node_is_on;i++)
27719  {
27720  // Boundary number
27721 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27722  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27723  << " Node is on boundary "
27724  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27725  << std::endl;
27726 #endif
27727  original_boundaries_node_is_on[i] =
27728  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27729  zeta_coordinates[i] =
27730  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
27731  }
27732 
27733  } // if (node_on_original_boundaries==2)
27734 #ifdef PARANOID
27735  else
27736  {
27737  if (node_on_original_boundaries != 0)
27738  {
27739  std::ostringstream error_message;
27740  error_message
27741  <<"The current node is not on an original boundary, this should\n"
27742  <<"be indicated by a zero flag. However, the read value for\n"
27743  <<"that flag is ("<<node_on_original_boundaries<<").\n\n";
27744  throw OomphLibError(
27745  error_message.str(),
27746  "RefineableTriangleMesh::construct_new_halo_node_helper()",
27747  OOMPH_EXCEPTION_LOCATION);
27748  } // if (node_on_original_boundaries != 0)
27749  }
27750 #endif
27751 
27752  // --------------------------------------------------------------
27753  // Check if the node was on a shared boundary with the iproc
27754  // processor
27755 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27756  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27757  << " Is node on shared boundary? "
27758  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27759  << std::endl;
27760 #endif
27761  const unsigned is_node_on_shared_boundary =
27762  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27763  if (is_node_on_shared_boundary == 1)
27764  {
27765  // How many shared boundaries does the node live on?
27766 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27767  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27768  << " Number of boundaries the node is on: "
27769  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27770  << std::endl;
27771 #endif
27772  const unsigned n_shd_bnd_node_is_on =
27773  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27774  Vector<unsigned> shd_bnds_node_is_on(n_shd_bnd_node_is_on);
27775  for (unsigned i=0;i<n_shd_bnd_node_is_on;i++)
27776  {
27777  // Shared boundary number
27778 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27779  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27780  << " Node is on boundary "
27781  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27782  << std::endl;
27783 #endif
27784  shd_bnds_node_is_on[i] =
27785  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27786  }
27787 
27788  // Get the index of the node on the shared boundary
27789 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27790  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27791  << " Index of node on boundary "
27792  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27793  << std::endl;
27794 #endif
27795  // Get the node index of the node on the shared boundary
27796  unsigned node_index_on_shared_boundary =
27797  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27798 
27799  // Get the pointer to the node with the received info.
27800  new_nod_pt =
27801  this->sorted_shared_boundary_node_pt(shd_bnds_node_is_on[0],
27802  node_index_on_shared_boundary);
27803 
27804  } // if (is_node_on_shared_boundary == 1)
27805 #ifdef PARANOID
27806  else
27807  {
27808  if (is_node_on_shared_boundary != 0)
27809  {
27810  std::ostringstream error_message;
27811  error_message
27812  <<"The current node is not on a shared boundary, this should\n"
27813  <<"be indicated by a zero flag. However, the read value for\n"
27814  <<"that flag is ("<<is_node_on_shared_boundary<<").\n\n";
27815  throw OomphLibError(
27816  error_message.str(),
27817  "RefineableTriangleMesh::construct_new_halo_node_helper()",
27818  OOMPH_EXCEPTION_LOCATION);
27819  } // if (node_on_shared_boundary != 0)
27820  }
27821 #endif
27822 
27823  // ------------------------------------------------------------
27824  // Is the node on a shared boundary with other processor?
27825 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27826  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27827  << " Is the node on shared boundaries with other processors "
27828  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27829  << std::endl;
27830 #endif
27831 
27832  // Is the node in shared boundaries no associated with the
27833  // receiver processor
27834  const unsigned is_the_node_in_shared_boundaries_with_other_processors =
27835  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27836 
27837  // The containers where to store the info.
27838  Vector<unsigned> other_processor_1;
27839  Vector<unsigned> other_processor_2;
27840  Vector<unsigned> other_shared_boundaries;
27841  Vector<unsigned> other_indexes;
27842 
27843  // How many shared bounaries with other processors the node lives on
27844  unsigned n_shd_bnd_with_other_procs_have_node = 0;
27845 
27846  // Is the node on shared boundaries with other processors
27847  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
27848  {
27849 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27850  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27851  << " In how many shared boundaries with other "
27852  << "processors is the node "
27853  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27854  << std::endl;
27855 #endif
27856 
27857  // How many nodes on other shared boundaries were found
27858  n_shd_bnd_with_other_procs_have_node =
27859  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27860 
27861  // Resize the containers
27862  other_processor_1.resize(n_shd_bnd_with_other_procs_have_node);
27863  other_processor_2.resize(n_shd_bnd_with_other_procs_have_node);
27864  other_shared_boundaries.resize(n_shd_bnd_with_other_procs_have_node);
27865  other_indexes.resize(n_shd_bnd_with_other_procs_have_node);
27866 
27867  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
27868  {
27869 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27870  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27871  << " Processor where the other shared boundary"
27872  << "has the node"
27873  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27874  << std::endl;
27875 #endif
27876  // Read the other processor 1
27877  other_processor_1[i] =
27878  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27879 
27880 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27881  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27882  << " Processor where the other shared boundary"
27883  << "has the node"
27884  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27885  << std::endl;
27886 #endif
27887  // Read the other processor 2
27888  other_processor_2[i] =
27889  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27890 
27891 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27892  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27893  << " Other shared boundary id where the node is on: "
27894  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27895  << std::endl;
27896 #endif
27897 
27898  // Read the other shared boundary id
27899  other_shared_boundaries[i] =
27900  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27901 
27902 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27903  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27904  << " Node index on the other shared boundary "
27905  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27906  << std::endl;
27907 #endif
27908 
27909  // Read the node index on the other shared boundary
27910  other_indexes[i] =
27911  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27912 
27913  } // for (i < n_shd_bnd_with_other_procs_have_node)
27914 
27915  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
27916 #ifdef PARANOID
27917  else
27918  {
27919  if (is_the_node_in_shared_boundaries_with_other_processors != 0)
27920  {
27921  std::ostringstream error_message;
27922  error_message
27923  <<"The current node is not on a shared boundary with\n"
27924  <<"other processors, this should be indicated by a zero flag.\n"
27925  <<"However, the read value for that flag is ("
27926  <<is_the_node_in_shared_boundaries_with_other_processors<<").\n\n";
27927  throw OomphLibError(
27928  error_message.str(),
27929  "RefineableTriangleMesh::construct_new_node_load_balance_helper()",
27930  OOMPH_EXCEPTION_LOCATION);
27931  }
27932  }
27933 #endif
27934 
27935  // ------------------------------------------------------------
27936  // Receive the info. to check if the node is on a haloed element
27937  // with any processor
27938 
27939  // Store the halo element number with jproc where the node was found
27940  Vector<Vector<unsigned> > halo_element_number(nproc);
27941  // Store the node number on the halo element where the node was found
27942  Vector<Vector<unsigned> > halo_node_number_in_halo_element(nproc);
27943 
27944  // Loop over the processors
27945  for (unsigned jproc = 0; jproc < nproc; jproc++)
27946  {
27947 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27948  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27949  << " The node is on "
27950  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27951  << " halo elements with " << jproc << " processor"
27952  << std::endl;
27953 #endif
27954  // Get the number of halo elements with jproc processor where the
27955  // node was found
27956  const unsigned n_jproc_halo_ele_node_is_on =
27957  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27958 
27959  // Resize the containers
27960  halo_element_number[jproc].resize(n_jproc_halo_ele_node_is_on);
27961  halo_node_number_in_halo_element[jproc].resize(n_jproc_halo_ele_node_is_on);
27962 
27963  // Read halo elements indexes (which are indexes of the halo
27964  // elements of the sender processor (iproc) with other processors
27965  // (included my_rank)
27966  for (unsigned i = 0; i < n_jproc_halo_ele_node_is_on; i++)
27967  {
27968  // Get the halo element index in the jproc processor
27969 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27970  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27971  << " The halo element index where the node is on "
27972  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27973  << std::endl;
27974 #endif
27975  // Get the node index on the halo element
27976  const unsigned halo_ele_index =
27977  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27978 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
27979  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
27980  << " The node index on the halo element where the node "
27981  << "is on "
27982  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
27983  << std::endl;
27984 #endif
27985  const unsigned node_index_on_halo_ele =
27986  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
27987 
27988  // Store the halo element number
27989  halo_element_number[jproc][i] = halo_ele_index;
27990  // Store the index of on the haloed element
27991  halo_node_number_in_halo_element[jproc][i] = node_index_on_halo_ele;
27992 
27993  } // for (i < n_jproc_halo_ele_node_is_on)
27994 
27995  } // for (jproc < nproc)
27996 
27997  // Store the node pointers obtained from the indicated halo elements
27998  // (use a set to check for the case when the node pointer is
27999  // different)
28000  std::set<Node*> set_haloed_node_pt;
28001 
28002  // Store the node pointer obtained from the haloed elements
28003  Node* haloed_node_pt = 0;
28004 
28005  // Flag to indicate if it is on a haloed element of the current
28006  // processor with the iproc processor. If this flag is true then
28007  // there is no need to read the info. to create the node, only copy
28008  // the node from the indicated haloed element-node
28009  bool on_haloed_element_with_iproc_processor = false;
28010  if (halo_element_number[my_rank].size() > 0)
28011  {
28012  // The node is part of the haloed element in the current processor
28013  // (my_rank) with the receiver processor
28014  on_haloed_element_with_iproc_processor = true;
28015 
28016  // Get the number of haloed elements in the current processor
28017  const unsigned n_haloed_indexes = halo_element_number[my_rank].size();
28018  // Loop over the different haloed indexes, and get the nodes
28019  // instances from all the indicated haloed elements (all of them
28020  // should be the same)
28021  for (unsigned i = 0; i < n_haloed_indexes; i++)
28022  {
28023  // Get the haloed element numbers where the node is on
28024  const unsigned haloed_index = halo_element_number[my_rank][i];
28025  // Get the node index on the haloed element
28026  const unsigned haloed_node_index =
28027  halo_node_number_in_halo_element[my_rank][i];
28028 
28029  // Get the haloed element (with iproc)
28030  FiniteElement* tmp_haloed_ele_pt = f_haloed_ele_pt[iproc][haloed_index];
28031  // Get the node on the indicated node number
28032  Node* tmp_haloed_node_pt = tmp_haloed_ele_pt->node_pt(haloed_node_index);
28033 
28034  // Set the pointer for the obtained haloed node
28035  haloed_node_pt = tmp_haloed_node_pt;
28036 
28037  // Add the node to the set of node pointers
28038  set_haloed_node_pt.insert(tmp_haloed_node_pt);
28039 
28040 #ifdef PARANOID
28041  if (set_haloed_node_pt.size() > 1)
28042  {
28043  std::ostringstream error_message;
28044  error_message
28045  <<"When adding the " << haloed_node_index << " node of the "
28046  << haloed_index << "-th haloed element\n"
28047  << "in the currrent processor with the " << iproc << " processor"
28048  << "it was found that\nthe node pointer is different from the other"
28049  << "instances of the node.\nIt means we have a repeated node."
28050  << "This are the node coordinates of the previous node instances\n"
28051  << "The last entry is for the just added node with a different node\n"
28052  << "pointer\n";
28053  for (std::set<Node*>::iterator it = set_haloed_node_pt.begin();
28054  it != set_haloed_node_pt.end(); it++)
28055  {
28056  error_message
28057  << "Node: ("<< (*it)->x(0)<<", "<<(*it)->x(1)<<")\n";
28058  }
28059  error_message << "\n";
28060  throw OomphLibError(
28061  error_message.str(),
28062  "RefineableTriangleMesh::construct_new_node_load_balance_helper()",
28063  OOMPH_EXCEPTION_LOCATION);
28064  }
28065 #endif
28066 
28067  } // for (i < n_haloed_indexes)
28068 
28069  } // if (halo_element_number[iproc].size() > 0)
28070 
28071  // Flag to indicate if the node has been found on a haloed element
28072  // of other processor with the iproc processor
28073  bool found_on_haloed_element_with_other_processor = false;
28074  // Loop over the processors (only until the iproc since no info. of
28075  // higher processors has been received)
28076  for (unsigned jproc = 0; jproc < iproc; jproc++)
28077  {
28078  // Is the node on a halo element with the jproc processor
28079  if (halo_element_number[jproc].size() > 0)
28080  {
28081  // Get the number of halo elements with the jproc processor
28082  const unsigned n_halo_indexes = halo_element_number[jproc].size();
28083  // Loop over the different halo indexes, and get the nodes
28084  // instances from all the indicated halo elements (all of them
28085  // should be the same)
28086  for (unsigned i = 0; i < n_halo_indexes; i++)
28087  {
28088  // Get the haloed element numbers where the node is on
28089  const unsigned haloed_index = halo_element_number[jproc][i];
28090  // Get the node index on the haloed element
28091  const unsigned haloed_node_index =
28092  halo_node_number_in_halo_element[jproc][i];
28093 
28094  // Have we received the indicated element? (Get the haloed
28095  // element on jproc with the iproc processor)
28096  std::map<unsigned,FiniteElement*>::iterator it_map =
28097  received_old_haloed_element_pt[jproc][iproc].find(haloed_index);
28098  // Have we received the indicated element?
28099  if (it_map != received_old_haloed_element_pt[jproc][iproc].end())
28100  {
28101  // Set the flag of found element in other processors haloed
28102  // element, in this case in haloed elements of processor
28103  // jproc wiht iproc processor
28104  found_on_haloed_element_with_other_processor = true;
28105 
28106  // Get the element
28107  FiniteElement* tmp_haloed_ele_pt = (*it_map).second;
28108  // Get the node on the indicated node number
28109  Node* tmp_haloed_node_pt =
28110  tmp_haloed_ele_pt->node_pt(haloed_node_index);
28111 
28112  // Set the pointer for the obtained haloed node
28113  haloed_node_pt = tmp_haloed_node_pt;
28114 
28115  // Add the node to the set of node pointers
28116  set_haloed_node_pt.insert(tmp_haloed_node_pt);
28117 
28118 #ifdef PARANOID
28119  if (set_haloed_node_pt.size() > 1)
28120  {
28121  std::ostringstream error_message;
28122  error_message
28123  <<"When adding the " << haloed_node_index << " node of the "
28124  << haloed_index << "-th haloed element "
28125  << "of the " << jproc << " processor\nwith the "
28126  << iproc << " processor, it was found that\n"
28127  << "the node pointer is different from the other\n"
28128  << "instances of the node.\nThis means we have a repeated node.\n"
28129  << "These are the node coordinates of the previous node "
28130  << "instances\n"
28131  << "The last entry is for the just added node with a different\n"
28132  << "node pointer\n";
28133  for (std::set<Node*>::iterator it = set_haloed_node_pt.begin();
28134  it != set_haloed_node_pt.end(); it++)
28135  {
28136  error_message
28137  << "Node: ("<< (*it)->x(0)<<", "<<(*it)->x(1)<<")\n";
28138  }
28139  error_message << "\n";
28140  throw OomphLibError(
28141  error_message.str(),
28142  "RefineableTriangleMesh::construct_new_node_load_balance_helper()",
28143  OOMPH_EXCEPTION_LOCATION);
28144  }
28145 #endif
28146 
28147  } // if (it_map != received_old_haloed_element_pt[jproc][iproc].end())
28148  // Have we received the element?
28149 
28150  } // for (i < n_haloed_indexes)
28151 
28152  } // if (halo_element_number[iproc].size() > 0)
28153 
28154  } // for (jproc < nproc)
28155 
28156  // If the node was found in the haloed elements of the current
28157  // processor with the iproc processor, or in the haloed elements of
28158  // any other processor with the iproc processor then copy the node
28159  // pointer (no problem if we overwrite the node info. it should be
28160  // the same node pointer)
28161  if (on_haloed_element_with_iproc_processor ||
28162  found_on_haloed_element_with_other_processor)
28163  {
28164  // Set the node pointer
28165  new_nod_pt = haloed_node_pt;
28166  }
28167 
28168  // Now we have all the info. to decide if the node should be created
28169  // or not
28170 
28171  // First check if the node is a shared boundary node, or if it has
28172  // been found on haloed elements
28173  if (is_node_on_shared_boundary == 1 ||
28174  (on_haloed_element_with_iproc_processor))
28175  {
28176  // We already have the node, we do not need to create it
28177 
28178  // Only check if we need to add boundary info. to the node
28179  if (node_on_original_boundaries==2)
28180  {
28181  // The node is a boundary node, add the boundary info. before
28182  // adding it to the domain
28183 
28184  // Associate the node to the given boundaries
28185  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
28186  {
28187  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
28188  // Establish the boundary coordinates for the node
28189  Vector<double> zeta(1);
28190  zeta[0] = zeta_coordinates[i];
28191  new_nod_pt->set_coordinates_on_boundary(
28192  original_boundaries_node_is_on[i],zeta);
28193  }
28194 
28195  } // if (node_on_original_boundaries==2)
28196 
28197  // Add the node to the domain
28198  new_nodes_on_domain.push_back(new_nod_pt);
28199 
28200  // Add the node to the element
28201  new_el_pt->node_pt(node_index) = new_nod_pt;
28202 
28203  } // if (is_node_on_shared_boundary == 1)
28204 
28205  // Now check if the node is on a shared boundary with another
28206  // processor, if that is the case try to find the node that may have
28207  // been already sent by the other processors
28208 
28209  // This flags indicates if the node was found, and then decide if it
28210  // is required to create the node
28211  bool found_node_in_other_shared_boundaries = false;
28212  // Flag to indicate whether the node should be created as a boundary
28213  // node or not. If the node lies on a shared boundary with other
28214  // processor the we create it as a boundary node. The processor from
28215  // which we are receiving info. (iproc) may not know that the node
28216  // lies on an original boundary. If the node lies on an original
28217  // boundary then its info. will be sent by another processor, then
28218  // we can set its boundary info. since the node was constructed as a
28219  // boundary node
28220  bool build_node_as_boundary_node = false;
28221 
28222  if (is_the_node_in_shared_boundaries_with_other_processors == 4)
28223  {
28224  // Build the node as a boundary node
28225  build_node_as_boundary_node = true;
28226 
28227  // Try to get the node pointer in case that the node has been
28228  // already sent by the other processors
28229 
28230  // Get the number of initial shared boundaries to correct the
28231  // index of the shared boundary
28232  const unsigned initial_shd_bnd_id = this->initial_shared_boundary_id();
28233 
28234  // Add the found nodes in the container, should be the same but
28235  // better check
28236  Vector<Node*> found_node_pt;
28237 
28238  // Now try to find the node in any of the other shared boundaries
28239  for (unsigned i = 0; i < n_shd_bnd_with_other_procs_have_node; i++)
28240  {
28241  unsigned oproc1 = other_processor_1[i];
28242  unsigned oproc2 = other_processor_2[i];
28243 
28244  // Check that we always check with the lower processors number
28245  // first
28246  if (oproc1 > oproc2)
28247  {
28248  oproc2 = oproc1;
28249  oproc1 = other_processor_2[i];
28250  } // if (oproc1 > oproc2)
28251 
28252  // Re-compute the shared boundary id between the other
28253  // processors
28254  const unsigned shd_bnd_id =
28255  other_shared_boundaries[i] - initial_shd_bnd_id;
28256  // Read the index
28257  const unsigned index = other_indexes[i];
28258 
28259  // Check if there are nodes received from the other processor
28260  // and with the given shared boundary
28261  const unsigned n_nodes_on_other_processor =
28262  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].size();
28263 
28264  if (n_nodes_on_other_processor > 0)
28265  {
28266  // Check if we can find the index of the node in that other
28267  // processor and shared boundary id
28268  std::map<unsigned, Node*>::iterator it =
28269  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].
28270  find(index);
28271 
28272  // If the index exist then get the node pointer
28273  if (it!=
28274  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
28275  {
28276  // Mark the node as found
28277  found_node_in_other_shared_boundaries = true;
28278  // Get the node pointer
28279  Node* tmp_node_pt =
28280  other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id][index];
28281  found_node_pt.push_back(tmp_node_pt);
28282  } // if (it!=
28283  // other_proc_shd_bnd_node_pt[oproc1][oproc2][shd_bnd_id].end())
28284 
28285  } // if (n_nodes_on_other_processor > 0)
28286 
28287  } // for (i < n_shd_bnd_with_other_procs_have_node)
28288 
28289  // If the node was found, then all their instances should be the
28290  // same but better check
28291  if (found_node_in_other_shared_boundaries)
28292  {
28293 #ifdef PARANOID
28294  const unsigned ntimes_node_found = found_node_pt.size();
28295  for (unsigned j = 1; j < ntimes_node_found; j++)
28296  {
28297  if (found_node_pt[j-1] != found_node_pt[j])
28298  {
28299  std::ostringstream error_message;
28300  error_message
28301  <<"The instances of the node that was found to be on a\n"
28302  <<"shared boundary with other processors are not the same,\n"
28303  <<"the coordinates for the nodes are these:\n"
28304  <<"(" << found_node_pt[j-1]->x(0) << ", "
28305  << found_node_pt[j-1]->x(1) << ")\n"
28306  <<"(" << found_node_pt[j]->x(0) << ", "
28307  << found_node_pt[j]->x(1) << ")\n"
28308  <<"Not be surprised if they are the same since the node is\n"
28309  <<"repeated!!!\n";
28310  throw OomphLibError(
28311  error_message.str(),
28312  "RefineableTriangleMesh::construct_new_halo_node_helper()",
28313  OOMPH_EXCEPTION_LOCATION);
28314 
28315  } // if (found_node_pt[j-1] != found_node_pt[j])
28316 
28317  } // for (j < ntimes_node_found)
28318 #endif
28319 
28320  // Check if the node is a shared boundary node from the current
28321  // processor and the iproc processor, if that is the case, and
28322  // the node is also on a shared boundary with other processor,
28323  // then the pointer should be the same!!!
28324  if (is_node_on_shared_boundary == 1)
28325  {
28326  // The pointer to the node is already assigned, it was
28327  // assigned when thenode was found to be on a shared boundary
28328  // with the iproc processor
28329  if (found_node_pt[0] != new_nod_pt)
28330  {
28331  std::ostringstream error_message;
28332  error_message
28333  <<"The pointer of the node that was found to be on a\n"
28334  <<"shared boundary with other processor(s) and the pointer\n"
28335  <<"of the node on shared boundary with the receiver\n"
28336  <<"processor (iproc) are not the same. This means we have a\n"
28337  << "repeated node)\n"
28338  <<"The coordinates for the nodes are:\n"
28339  <<"(" << found_node_pt[0]->x(0) << ", "
28340  << found_node_pt[0]->x(1) << ")\n"
28341  <<"(" << new_nod_pt->x(0) << ", "
28342  << new_nod_pt->x(1) << ")\n"
28343  <<"Not to be surprised if they are the same since the node is\n"
28344  <<"repeated!!!\n";
28345  throw OomphLibError(
28346  error_message.str(),
28347  "RefineableTriangleMesh::construct_new_halo_node_helper()",
28348  OOMPH_EXCEPTION_LOCATION);
28349  } // if (found_node_pt[0] != new_nod_pt)
28350 
28351  } // if (is_node_on_shared_boundary == 1)
28352  else
28353  {
28354  // Take the first instance of the node in case that it was
28355  // found and is not on a shared boundary with the iproc
28356  // processor
28357  new_nod_pt = found_node_pt[0];
28358  }
28359 
28360  } // if (found_node_in_other_shared_boundaries)
28361 
28362  } // if (is_the_node_in_shared_boundaries_with_other_processors == 4)
28363 
28364  // -----------------------------------------------------------------
28365  // Create the node or read the received info if the node is not on a
28366  // shared boundary with the iproc processor and if the node is not
28367  // part of the haloed elements with the iproc processor in the
28368  // current processors
28369  if (is_node_on_shared_boundary != 1 &&
28370  !on_haloed_element_with_iproc_processor)
28371  {
28372  // If the node is on a shared boundary with other processor we
28373  // need to read all the info. since the processor that sent the
28374  // info. did not know that the node is part of another shared
28375  // boundary
28376 
28377  // If the node is not a shared boundary (with any processor), or
28378  // if this is the first time that the info. of the node is
28379  // received from any of the processors with which is has a shared
28380  // boundary, then we create the node
28381 
28382  // Is the node a boundary node or should it be build as a boundary
28383  // node because it is on a shared boundary with other processors
28384  if (node_on_original_boundaries==2 || build_node_as_boundary_node)
28385  {
28386  // Check if necessary to create the node, or if it has been
28387  // already found in shared boundaries with other processors or
28388  // in the haloed elements with of other processors with the
28389  // iproc processor
28390  if (!found_node_in_other_shared_boundaries ||
28391  !found_on_haloed_element_with_other_processor)
28392  {
28393  // Construct a boundary node
28394  if (time_stepper_pt!=0)
28395  {
28396  new_nod_pt=new_el_pt->construct_boundary_node(node_index,
28397  time_stepper_pt);
28398  }
28399  else
28400  {
28401  new_nod_pt=new_el_pt->construct_boundary_node(node_index);
28402  }
28403 
28404  } // if (!found_node_in_other_shared_boundaries ||
28405  // !found_on_haloed_element_with_other_processor)
28406  else
28407  {
28408  // If the node was found then assign the node to the element
28409  new_el_pt->node_pt(node_index) = new_nod_pt;
28410  } // else if (!found_node_in_other_shared_boundaries ||
28411  // !found_on_haloed_element_with_other_processor)
28412 
28413  // Associate the node to the given boundaries
28414  for (unsigned i = 0; i < n_original_boundaries_node_is_on; i++)
28415  {
28416  add_boundary_node(original_boundaries_node_is_on[i], new_nod_pt);
28417  // Establish the boundary coordinates for the node
28418  Vector<double> zeta(1);
28419  zeta[0] = zeta_coordinates[i];
28420  new_nod_pt->set_coordinates_on_boundary(
28421  original_boundaries_node_is_on[i],zeta);
28422  }
28423 
28424  } // if (node is on an original boundary)
28425  else
28426  {
28427  // Check if necessary to create the node, or if it has been
28428  // already found in shared boundaries with other processors or
28429  // in the haloed elements with of other processors with the
28430  // iproc processor
28431  if (!found_node_in_other_shared_boundaries ||
28432  !found_on_haloed_element_with_other_processor)
28433  {
28434  // Construct an ordinary (non-boundary) node
28435  if (time_stepper_pt!=0)
28436  {
28437  new_nod_pt=new_el_pt->construct_node(node_index, time_stepper_pt);
28438  }
28439  else
28440  {
28441  new_nod_pt=new_el_pt->construct_node(node_index);
28442  }
28443  } // if (!found_node_in_other_shared_boundaries ||
28444  // !found_on_haloed_element_with_other_processor)
28445  else
28446  {
28447  // If the node was found then assign the node to the element
28448  new_el_pt->node_pt(node_index) = new_nod_pt;
28449  } // else // if (!found_node_in_other_shared_boundaries ||
28450  // !found_on_haloed_element_with_other_processor)
28451 
28452  } // else (the node is not a boundary node)
28453 
28454  // ... and gather all its information
28455 
28456  // If the node was found or not in other shared boundaries, this
28457  // is the first time the node is received from this processor
28458  // (iproc), therefore it is added to the vector of nodes received
28459  // from this processor (iproc)
28460  new_nodes_on_domain.push_back(new_nod_pt);
28461 
28462  // Check if necessary to state all the info. to the node if it has
28463  // been already found in shared boundaries with other processors
28464  // or in the haloed elements with of other processors with the
28465  // iproc processor
28466  if (!found_node_in_other_shared_boundaries ||
28467  !found_on_haloed_element_with_other_processor)
28468  {
28469  // Add the node to the general node storage
28470  this->add_node_pt(new_nod_pt);
28471  } // if (!found_node_in_other_shared_boundaries ||
28472  // !found_on_haloed_element_with_other_processor)
28473 
28474  // Is the new constructed node Algebraic?
28475  AlgebraicNode* new_alg_nod_pt=dynamic_cast<AlgebraicNode*>
28476  (new_nod_pt);
28477 
28478  // If it is algebraic, its node update functions will
28479  // not yet have been set up properly
28480  if (new_alg_nod_pt!=0)
28481  {
28482  // The AlgebraicMesh is the external mesh
28483  AlgebraicMesh* alg_mesh_pt=dynamic_cast<AlgebraicMesh*>(this);
28484 
28485  /// The first entry of All_alg_nodal_info contains
28486  /// the default node update id
28487  /// e.g. for the quarter circle there are
28488  /// "Upper_left_box", "Lower right box" etc...
28489 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28490  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28491  << " Alg node update id "
28492  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28493  << std::endl;
28494 #endif
28495 
28496  unsigned update_id=Flat_packed_unsigneds
28497  [Counter_for_flat_packed_unsigneds++];
28498 
28499  Vector<double> ref_value;
28500 
28501  // The size of this vector is in the next entry
28502  // of All_alg_nodal_info
28503 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28504  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28505  << " Alg node # of ref values "
28506  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28507  << std::endl;
28508 #endif
28509  unsigned n_ref_val=Flat_packed_unsigneds
28510  [Counter_for_flat_packed_unsigneds++];
28511 
28512  // The reference values themselves are in
28513  // All_alg_ref_value
28514  ref_value.resize(n_ref_val);
28515  for (unsigned i_ref=0;i_ref<n_ref_val;i_ref++)
28516  {
28517  ref_value[i_ref]=Flat_packed_doubles
28518  [Counter_for_flat_packed_doubles++];
28519  }
28520 
28521  Vector<GeomObject*> geom_object_pt;
28522  /// again we need the size of this vector as it varies
28523  /// between meshes; we also need some indication
28524  /// as to which geometric object should be used...
28525 
28526  // The size of this vector is in the next entry
28527  // of All_alg_nodal_info
28528 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28529  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28530  << " Alg node # of geom objects "
28531  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28532  << std::endl;
28533 #endif
28534  unsigned n_geom_obj=Flat_packed_unsigneds
28535  [Counter_for_flat_packed_unsigneds++];
28536 
28537  // The remaining indices are in the rest of
28538  // All_alg_nodal_info
28539  geom_object_pt.resize(n_geom_obj);
28540  for (unsigned i_geom=0;i_geom<n_geom_obj;i_geom++)
28541  {
28542 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28543  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28544  << " Alg node: geom object index "
28545  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28546  << std::endl;
28547 #endif
28548  unsigned geom_index=Flat_packed_unsigneds
28549  [Counter_for_flat_packed_unsigneds++];
28550  // This index indicates which of the AlgebraicMesh's
28551  // stored geometric objects should be used
28552  // (0 is a null pointer; everything else should have
28553  // been filled in by the specific Mesh). If it
28554  // hasn't been filled in then the update_node_update
28555  // call should fix it
28556  geom_object_pt[i_geom]=alg_mesh_pt->
28557  geom_object_list_pt(geom_index);
28558  }
28559 
28560  // Check if necessary to state all the info. to the node if it
28561  // has been already found in shared boundaries with other
28562  // processors or in the haloed elements with of other processors
28563  // with the iproc processor
28564  if (!found_node_in_other_shared_boundaries ||
28565  !found_on_haloed_element_with_other_processor)
28566  {
28567  /// For the received update_id, ref_value, geom_object
28568  /// call add_node_update_info
28569  new_alg_nod_pt->add_node_update_info
28570  (update_id,alg_mesh_pt,geom_object_pt,ref_value);
28571 
28572  /// Now call update_node_update
28573  alg_mesh_pt->update_node_update(new_alg_nod_pt);
28574 
28575  } // if (!found_node_in_other_shared_boundaries ||
28576  // !found_on_haloed_element_with_other_processor)
28577 
28578  } // if (new_alg_nod_pt!=0)
28579 
28580  // Check if necessary to state all the info. to the node if it has
28581  // been already found in shared boundaries with other processors
28582  // or in the haloed elements with of other processors with the
28583  // iproc processor
28584  if (!found_node_in_other_shared_boundaries ||
28585  !found_on_haloed_element_with_other_processor)
28586  {
28587  // Is the node a MacroElementNodeUpdateNode?
28588  MacroElementNodeUpdateNode* macro_nod_pt=
28589  dynamic_cast<MacroElementNodeUpdateNode*>(new_nod_pt);
28590 
28591  if (macro_nod_pt!=0)
28592  {
28593  // Need to call set_node_update_info; this requires
28594  // a Vector<GeomObject*> (taken from the mesh)
28595  Vector<GeomObject*> geom_object_vector_pt;
28596 
28597  // Access the required geom objects from the
28598  // MacroElementNodeUpdateMesh
28599  MacroElementNodeUpdateMesh* macro_mesh_pt=
28600  dynamic_cast<MacroElementNodeUpdateMesh*>(this);
28601  geom_object_vector_pt=
28602  macro_mesh_pt->geom_object_vector_pt();
28603 
28604  // Get local coordinate of node in new element
28605  Vector<double> s_in_macro_node_update_element;
28606  new_el_pt->local_coordinate_of_node
28607  (node_index,s_in_macro_node_update_element);
28608 
28609  // Set node update info for this node
28610  macro_nod_pt->set_node_update_info
28611  (new_el_pt,s_in_macro_node_update_element,
28612  geom_object_vector_pt);
28613  }
28614 
28615  } // if (!found_node_in_other_shared_boundaries ||
28616  // !found_on_haloed_element_with_other_processor)
28617 
28618  // If there are additional values, resize the node
28619  unsigned n_new_val=new_nod_pt->nvalue();
28620 
28621  // Check if necessary to state all the info. to the node if it has
28622  // been already found in shared boundaries with other processors
28623  // or in the haloed elements with of other processors with the
28624  // iproc processor
28625  if (!found_node_in_other_shared_boundaries ||
28626  !found_on_haloed_element_with_other_processor)
28627  {
28628  if (n_val>n_new_val)
28629  {
28630  // If it has been necessary to resize then it may be becuse
28631  // the node is on a FSI boundary, if that is the case we need
28632  // to set a map for these external values
28633 
28634  // Cast to a boundary node
28635  BoundaryNodeBase *bnod_pt =
28636  dynamic_cast<BoundaryNodeBase*>(new_nod_pt);
28637 
28638  // Create storage, if it doesn't already exist, for the map
28639  // that will contain the position of the first entry of
28640  // this face element's additional values,
28641  if(bnod_pt->index_of_first_value_assigned_by_face_element_pt()==0)
28642  {
28643  bnod_pt->index_of_first_value_assigned_by_face_element_pt()=
28644  new std::map<unsigned, unsigned>;
28645  }
28646 
28647  // Get pointer to the map
28648  std::map<unsigned, unsigned>* map_pt=
28649  bnod_pt->index_of_first_value_assigned_by_face_element_pt();
28650 
28651  // The id of the face to which this node belong in the bulk
28652  // element
28653  const unsigned id_face = 0;
28654  // We only resize the node values Vector if we haven't done it yet
28655  std::map<unsigned, unsigned>::const_iterator p=map_pt->find(id_face);
28656 
28657  // If this node hasn't been resized for current id
28658  if(p==map_pt->end())
28659  {
28660  // assign the face element id and the position of the
28661  //first entry to the boundary node
28662  (*map_pt)[id_face] = n_new_val;
28663 
28664  // resize the node vector of values
28665  new_nod_pt->resize(n_val);
28666  }
28667 
28668  } // if (n_val>n_new_val)
28669 
28670  } // if (!found_node_in_other_shared_boundaries ||
28671  // !found_on_haloed_element_with_other_processor)
28672 
28673  // Is the new node a SolidNode?
28674  SolidNode* solid_nod_pt=dynamic_cast<SolidNode*>(new_nod_pt);
28675  if (solid_nod_pt!=0)
28676  {
28677  unsigned n_solid_val=solid_nod_pt->variable_position_pt()->nvalue();
28678  for (unsigned i_val=0;i_val<n_solid_val;i_val++)
28679  {
28680  for (unsigned t=0;t<n_prev;t++)
28681  {
28682  double read_data =
28683  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
28684 
28685  // Check if necessary to state all the info. to the node if
28686  // it has been already found in shared boundaries with other
28687  // processors or in the haloed elements with of other
28688  // processors with the iproc processor
28689  if (!found_node_in_other_shared_boundaries ||
28690  !found_on_haloed_element_with_other_processor)
28691  {
28692  solid_nod_pt->variable_position_pt()->
28693  set_value(t, i_val, read_data);
28694  } // if (!found_node_in_other_shared_boundaries ||
28695  // !found_on_haloed_element_with_other_processor)
28696 
28697  }
28698 
28699  }
28700 
28701 #ifdef ANNOTATE_REFINEABLE_TRIANGLE_MESH_COMMUNICATION_LOAD_BALANCE
28702  oomph_info << "Rec:" << Counter_for_flat_packed_unsigneds
28703  << " Number of values solid node: "
28704  << Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds]
28705  << std::endl;
28706 #endif
28707  const unsigned nvalues_solid_node =
28708  Flat_packed_unsigneds[Counter_for_flat_packed_unsigneds++];
28709  Vector<double> values_solid_node(nvalues_solid_node);
28710  for (unsigned i = 0; i < nvalues_solid_node; i++)
28711  {
28712  values_solid_node[i] =
28713  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
28714  }
28715 
28716  // Check if necessary to state all the info. to the node if it
28717  // has been already found in shared boundaries with other
28718  // processors or in the haloed elements with of other processors
28719  // with the iproc processor
28720  if (!found_node_in_other_shared_boundaries ||
28721  !found_on_haloed_element_with_other_processor)
28722  {
28723  unsigned index = 0;
28724  solid_nod_pt->read_values_from_vector(values_solid_node, index);
28725  } // if (!found_node_in_other_shared_boundaries ||
28726  // !found_on_haloed_element_with_other_processor)
28727 
28728  }
28729 
28730  // Get copied history values
28731  // unsigned n_val=new_nod_pt->nvalue();
28732  for (unsigned i_val=0;i_val<n_val;i_val++)
28733  {
28734  for (unsigned t=0;t<n_prev;t++)
28735  {
28736  double read_data =
28737  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
28738 
28739  // Check if necessary to state all the info. to the node if it
28740  // has been already found in shared boundaries with other
28741  // processors or in the haloed elements with of other
28742  // processors with the iproc processor
28743  if (!found_node_in_other_shared_boundaries ||
28744  !found_on_haloed_element_with_other_processor)
28745  {
28746  new_nod_pt->set_value(t, i_val, read_data);
28747  } // if (!found_node_in_other_shared_boundaries ||
28748  // !found_on_haloed_element_with_other_processor)
28749 
28750  }
28751 
28752  }
28753 
28754  // Get copied history values for positions
28755  unsigned n_dim=new_nod_pt->ndim();
28756  for (unsigned idim=0;idim<n_dim;idim++)
28757  {
28758  for (unsigned t=0;t<n_prev;t++)
28759  {
28760  double read_data =
28761  Flat_packed_doubles[Counter_for_flat_packed_doubles++];
28762 
28763  // Check if necessary to state all the info. to the node if it
28764  // has been already found in shared boundaries with other
28765  // processors or in the haloed elements with of other
28766  // processors with the iproc processor
28767  if (!found_node_in_other_shared_boundaries ||
28768  !found_on_haloed_element_with_other_processor)
28769  {
28770  // Copy to coordinate
28771  new_nod_pt->x(t,idim) = read_data;
28772 // DEBP(new_nod_pt->x(t,idim));
28773  } // if (!found_node_in_other_shared_boundaries ||
28774  // !found_on_haloed_element_with_other_processor)
28775  }
28776  }
28777 
28778  } // if (is_node_on_shared_boundary != 1)
28779 
28780  // If the node was not found in other shared boundaries (possibly
28781  // because it is the first time the node has been sent) then copy
28782  // the node to the shared boundaries where it should be, use the
28783  // special container for this cases
28784  if (n_shd_bnd_with_other_procs_have_node > 0 && // The node is on
28785  // shared
28786  // boundaries with
28787  // other processors
28788  !found_node_in_other_shared_boundaries) // The node has not
28789  // been previously
28790  // set as with
28791  // shared with
28792  // other processors
28793  // (first time)
28794  {
28795 
28796  // Update the node pointer in all the references of the node
28797  this->update_other_proc_shd_bnd_node_helper(new_nod_pt,
28798  other_proc_shd_bnd_node_pt,
28799  other_processor_1,
28800  other_processor_2,
28801  other_shared_boundaries,
28802  other_indexes,
28803  global_node_names,
28804  node_name_to_global_index,
28805  global_shared_node_pt);
28806 
28807  } // if (!found_node_in_other_shared_boundaries)
28808 
28809  }
28810 
28811 #endif // #ifdef OOMPH_HAS_MPI
28812 
28813  //======================================================================
28814  /// \short Get the nodes on the boundary (b), these are stored in the
28815  /// segment they belong (also used by the load balance method to
28816  /// re-set the number of segments per boundary after load balance has
28817  /// taken place)
28818  //======================================================================
28819  template <class ELEMENT>
28821  const unsigned &b, Vector<Vector<Node*> > &tmp_segment_nodes)
28822  {
28823  // Clear the data structure were to return the nodes
28824  tmp_segment_nodes.clear();
28825 
28826  // Temporary storage for face elements
28827  Vector<FiniteElement*> face_el_pt;
28828 
28829  // Temporary storage for number of elements adjacent to the boundary
28830  unsigned nel = 0;
28831 
28832  // Temporary storage for elements adjacent to the boundary that have
28833  // a common edge (related with internal boundaries)
28834  unsigned n_repeated_ele = 0;
28835 
28836  // Get the number of regions
28837  const unsigned n_regions = this->nregion();
28838 
28839  // Temporary storage for already visited pair of nodes (edges)
28840  Vector < std::pair<Node*, Node *> > done_nodes_pt;
28841 
28842  // Are there more than one region?
28843  if (n_regions > 1)
28844  {
28845  for (unsigned rr = 0 ; rr < n_regions; rr++)
28846  {
28847  const unsigned region_id =
28848  static_cast<unsigned>(this->Region_attribute[rr]);
28849 
28850  // Loop over all elements on boundaries in region rr
28851  const unsigned nel_in_region =
28852  this->nboundary_element_in_region(b, region_id);
28853 
28854  // Number of repeated element in region
28855  unsigned nel_repeated_in_region = 0;
28856 
28857  // Only bother to do anything else, if there are elements
28858  // associated with the boundary and the current region
28859  if (nel_in_region > 0)
28860  {
28861  // Flag that activates when a repeated face element is found,
28862  // possibly because we are dealing with an internal boundary
28863  bool repeated = false;
28864 
28865  // Loop over the bulk elements adjacent to boundary b
28866  for (unsigned e = 0; e < nel_in_region; e++)
28867  {
28868  // Get pointer to the bulk element that is adjacent to boundary b
28869  FiniteElement* bulk_elem_pt =
28870  this->boundary_element_in_region_pt(b, region_id, e);
28871 
28872 #ifdef OOMPH_HAS_MPI
28873  // In a distributed mesh only work with nonhalo elements
28874  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
28875  {
28876  // Increase the number of repeated elements
28877  n_repeated_ele++;
28878  // Go for the next element
28879  continue;
28880  }
28881 #endif
28882 
28883  //Find the index of the face of element e along boundary b
28884  int face_index =
28885  this->face_index_at_boundary_in_region(b, region_id, e);
28886 
28887  // Before adding the new element we need to be sure that the
28888  // edge that this element represents has not been already
28889  // added
28890  FiniteElement* tmp_ele_pt = new DummyFaceElement<ELEMENT> (
28891  bulk_elem_pt, face_index);
28892 
28893  // Number of nodes in the face element
28894  const unsigned n_nodes = tmp_ele_pt->nnode();
28895 
28896  std::pair<Node*, Node*> tmp_pair =
28897  std::make_pair(tmp_ele_pt->node_pt(0),
28898  tmp_ele_pt->node_pt(n_nodes - 1));
28899 
28900  std::pair<Node*, Node*> tmp_pair_inverse =
28901  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
28902  tmp_ele_pt->node_pt(0));
28903 
28904  // Search for repeated nodes
28905  unsigned n_done_nodes = done_nodes_pt.size();
28906  for (unsigned l = 0; l < n_done_nodes; l++)
28907  {
28908  if (tmp_pair == done_nodes_pt[l] || tmp_pair_inverse
28909  == done_nodes_pt[l])
28910  {
28911  nel_repeated_in_region++;
28912  repeated = true;
28913  break;
28914  }
28915 
28916  } // for (l < n_done_nodes)
28917 
28918  // Create new face element?
28919  if (!repeated)
28920  {
28921  // Add the pair of nodes (edge) to the node dones
28922  done_nodes_pt.push_back(tmp_pair);
28923  // Add the face element to the storage
28924  face_el_pt.push_back(tmp_ele_pt);
28925  }
28926  else
28927  {
28928  // Clean up
28929  delete tmp_ele_pt;
28930  tmp_ele_pt = 0;
28931  }
28932 
28933  // Re-start
28934  repeated = false;
28935 
28936  } // for (e < nel_in_region)
28937 
28938  // Add on the number of elements in the boundary with the
28939  // current region
28940  nel += nel_in_region;
28941 
28942  // Add on the number of repeated elements
28943  n_repeated_ele += nel_repeated_in_region;
28944 
28945  } // if (nel_in_region > 0)
28946 
28947  } // for (rr < n_regions)
28948 
28949  } // if (n_regions > 1)
28950  //Otherwise it's just the normal boundary functions
28951  else
28952  {
28953  // Assign the number of boundary elements
28954  nel = this->nboundary_element(b);
28955 
28956  //Only bother to do anything else, if there are elements
28957  if (nel > 0)
28958  {
28959  // Flag that activates when a repeated face element is found,
28960  // possibly because we are dealing with an internal boundary
28961  bool repeated = false;
28962 
28963  // Loop over the bulk elements adjacent to boundary b
28964  for (unsigned e = 0; e < nel; e++)
28965  {
28966  // Get pointer to the bulk element that is adjacent to boundary b
28967  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
28968 
28969 #ifdef OOMPH_HAS_MPI
28970  // In a distributed mesh only work with nonhalo elements
28971  if (this->is_mesh_distributed() && bulk_elem_pt->is_halo())
28972  {
28973  // Increase the number of repeated elements
28974  n_repeated_ele++;
28975  // Go for the next element
28976  continue;
28977  }
28978 #endif
28979 
28980  //Find the index of the face of element e along boundary b
28981  int face_index = this->face_index_at_boundary(b, e);
28982 
28983  // Before adding the new element we need to be sure that the
28984  // edge that this element represent has not been already added
28985  FiniteElement* tmp_ele_pt = new DummyFaceElement<ELEMENT> (
28986  bulk_elem_pt, face_index);
28987 
28988  // Number of nodes in the face element
28989  const unsigned n_nodes = tmp_ele_pt->nnode();
28990 
28991  std::pair<Node*, Node*> tmp_pair =
28992  std::make_pair(tmp_ele_pt->node_pt(0),
28993  tmp_ele_pt->node_pt(n_nodes - 1));
28994 
28995  std::pair<Node*, Node*> tmp_pair_inverse =
28996  std::make_pair(tmp_ele_pt->node_pt(n_nodes - 1),
28997  tmp_ele_pt->node_pt(0));
28998 
28999  // Search for repeated nodes
29000  unsigned n_done_nodes = done_nodes_pt.size();
29001  for (unsigned l = 0; l < n_done_nodes; l++)
29002  {
29003  if (tmp_pair == done_nodes_pt[l] || tmp_pair_inverse
29004  == done_nodes_pt[l])
29005  {
29006  n_repeated_ele++;
29007  repeated = true;
29008  break;
29009  }
29010 
29011  } // for (l < n_done_nodes)
29012 
29013  // Create new face element
29014  if (!repeated)
29015  {
29016  // Add the pair of nodes (edge) to the node dones
29017  done_nodes_pt.push_back(tmp_pair);
29018  // Add the face element to the storage
29019  face_el_pt.push_back(tmp_ele_pt);
29020  }
29021  else
29022  {
29023  // Free the repeated bulk element!!
29024  delete tmp_ele_pt;
29025  tmp_ele_pt = 0;
29026  }
29027 
29028  // Re-start
29029  repeated = false;
29030 
29031  } // for (e < nel)
29032 
29033  } // if (nel > 0)
29034 
29035  } // else if (n_regions > 1)
29036 
29037  // Substract the repeated elements
29038  nel -= n_repeated_ele;
29039 
29040 #ifdef PARANOID
29041  if (nel!=face_el_pt.size())
29042  {
29043  std::ostringstream error_message;
29044  error_message
29045  << "The independet counting of face elements ("<<nel<<") for "
29046  << "boundary ("<<b<<") is different\n"
29047  << "from the real number of face elements in the container ("
29048  << face_el_pt.size() <<")\n";
29049  throw OomphLibError(error_message.str(),
29050  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29051  OOMPH_EXCEPTION_LOCATION);
29052  }
29053 #endif
29054 
29055  //Only bother to do anything else, if there are elements
29056  if (nel > 0)
29057  {
29058  // Assign the number of nonhalo face elements
29059  const unsigned nnon_halo_face_elements = nel;
29060 
29061  // The vector of list to store the "segments" that compound the
29062  // boundary (segments may appear only in a distributed mesh)
29063  Vector<std::list<FiniteElement*> > segment_sorted_ele_pt;
29064 
29065  // Number of already sorted face elements (only nonhalo face
29066  // elements for a distributed mesh)
29067  unsigned nsorted_face_elements = 0;
29068 
29069  // Keep track of who's done (in a distributed mesh this apply to
29070  // nonhalo only)
29071  std::map<FiniteElement*, bool> done_ele;
29072 
29073  // Keep track of which element is inverted (in distributed mesh
29074  // the elements may be inverted with respect to the segment they
29075  // belong)
29076  std::map<FiniteElement*, bool> is_inverted;
29077 
29078  // Iterate until all possible segments have been created. In a non
29079  // distributed mesh there is only one segment which defines the
29080  // complete boundary
29081  while(nsorted_face_elements < nnon_halo_face_elements)
29082  {
29083  // The ordered list of face elements (in a distributed mesh a
29084  // collection of continuous face elements define a segment)
29085  std::list<FiniteElement*> sorted_el_pt;
29086 
29087 #ifdef PARANOID
29088  // Select an initial element for the segment
29089  bool found_initial_face_element = false;
29090 #endif
29091 
29092  FiniteElement* ele_face_pt = 0;
29093 
29094  unsigned iface = 0;
29095 #ifdef OOMPH_HAS_MPI
29096  if (this->is_mesh_distributed())
29097  {
29098  for (iface = 0; iface < nel; iface++)
29099  {
29100  ele_face_pt = face_el_pt[iface];
29101  // If not done then take it as initial face element
29102  if (!done_ele[ele_face_pt])
29103  {
29104 #ifdef PARANOID
29105  // Set the flag to indicate the initial element was
29106  // found
29107  found_initial_face_element = true;
29108 #endif
29109  // Increase the number of sorted face elements
29110  nsorted_face_elements++;
29111  // Set the index to the next face element
29112  iface++;
29113  // Add the face element in the container
29114  sorted_el_pt.push_back(ele_face_pt);
29115  // Mark as done
29116  done_ele[ele_face_pt] = true;
29117  break;
29118  } // if (!done_el[ele_face_pt])
29119  } // for (iface < nel)
29120  } // if (this->is_mesh_distributed())
29121  else
29122  {
29123 #endif // #ifdef OOMPH_HAS_MPI
29124 
29125  // When the mesh is not distributed just take the first
29126  // element and put it in the ordered list
29127  ele_face_pt = face_el_pt[0];
29128 #ifdef PARANOID
29129  // Set the flag to indicate the initial element was found
29130  found_initial_face_element = true;
29131 #endif
29132  // Increase the number of sorted face elements
29133  nsorted_face_elements++;
29134  // Set the index to the next face element
29135  iface = 1;
29136  // Add the face element in the container
29137  sorted_el_pt.push_back(ele_face_pt);
29138  // Mark as done
29139  done_ele[ele_face_pt] = true;
29140 #ifdef OOMPH_HAS_MPI
29141  } // else if (this->is_mesh_distributed())
29142 #endif
29143 
29144 #ifdef PARANOID
29145  if (!found_initial_face_element)
29146  {
29147  std::ostringstream error_message;
29148  error_message
29149  <<"Could not find an initial face element for the current segment\n";
29150  throw OomphLibError(error_message.str(),
29151  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29152  OOMPH_EXCEPTION_LOCATION);
29153  }
29154 #endif
29155 
29156  // Number of nodes in the face element
29157  const unsigned nnod = ele_face_pt->nnode();
29158 
29159  // Left and rightmost nodes (the left and right nodes of the
29160  // current face element)
29161  Node* left_node_pt = ele_face_pt->node_pt(0);
29162  Node* right_node_pt = ele_face_pt->node_pt(nnod - 1);
29163 
29164  // Continue iterating if a new face element has been added to
29165  // the list
29166  bool face_element_added = false;
29167 
29168  // While a new face element has been added to the set of sorted
29169  // face elements continue iterating
29170  do
29171  {
29172  // Start from the next face element since we have already
29173  // added the previous one as the initial face element (any
29174  // previous face element had to be added on previous
29175  // iterations)
29176  for (unsigned iiface=iface;iiface<nel;iiface++)
29177  {
29178  // Re-start flag
29179  face_element_added = false;
29180 
29181  // Get the candidate element
29182  ele_face_pt = face_el_pt[iiface];
29183 
29184  // Check that the candidate element has not been done and is
29185  // not a halo element
29186  if (!done_ele[ele_face_pt])
29187  {
29188  // Get the left and right nodes of the current element
29189  Node* local_left_node_pt = ele_face_pt->node_pt(0);
29190  Node* local_right_node_pt = ele_face_pt->node_pt(nnod - 1);
29191 
29192  // New element fits at the left of segment and is not inverted
29193  if (left_node_pt == local_right_node_pt)
29194  {
29195  left_node_pt = local_left_node_pt;
29196  sorted_el_pt.push_front(ele_face_pt);
29197  is_inverted[ele_face_pt] = false;
29198  face_element_added = true;
29199  }
29200  // New element fits at the left of segment and is inverted
29201  else if (left_node_pt == local_left_node_pt)
29202  {
29203  left_node_pt = local_right_node_pt;
29204  sorted_el_pt.push_front(ele_face_pt);
29205  is_inverted[ele_face_pt] = true;
29206  face_element_added = true;
29207  }
29208  // New element fits on the right of segment and is not inverted
29209  else if (right_node_pt == local_left_node_pt)
29210  {
29211  right_node_pt = local_right_node_pt;
29212  sorted_el_pt.push_back(ele_face_pt);
29213  is_inverted[ele_face_pt] = false;
29214  face_element_added = true;
29215  }
29216  // New element fits on the right of segment and is inverted
29217  else if (right_node_pt == local_right_node_pt)
29218  {
29219  right_node_pt = local_left_node_pt;
29220  sorted_el_pt.push_back(ele_face_pt);
29221  is_inverted[ele_face_pt] = true;
29222  face_element_added = true;
29223  }
29224 
29225  if (face_element_added)
29226  {
29227  // Mark the face element as done
29228  done_ele[ele_face_pt] = true;
29229  nsorted_face_elements++;
29230  break;
29231  }
29232 
29233  } // if (!done_el[ele_face_pt])
29234 
29235  } // for (iiface<nnon_halo_face_element)
29236 
29237  }while(face_element_added &&
29238  (nsorted_face_elements < nnon_halo_face_elements));
29239 
29240  // Store the created segment in the vector of segments
29241  segment_sorted_ele_pt.push_back(sorted_el_pt);
29242 
29243  } // while(nsorted_face_elements < nnon_halo_face_elements);
29244 
29245  // The number of boundary segments in this processor
29246  const unsigned nsegments = segment_sorted_ele_pt.size();
29247 
29248 #ifdef PARANOID
29249  if (nnon_halo_face_elements > 0 && nsegments == 0)
29250  {
29251  std::ostringstream error_message;
29252  error_message
29253  << "The number of segments is zero, but the number of nonhalo\n"
29254  << "elements is: (" << nnon_halo_face_elements << ")\n";
29255  throw OomphLibError(error_message.str(),
29256  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29257  OOMPH_EXCEPTION_LOCATION);
29258  } // if (nnon_halo_face_elements > 0 && nsegments == 0)
29259 #endif
29260 
29261  // Go through all the segments, visit each face element in order
29262  // and get the nodes based that represent the boundary segment
29263 
29264  // Resize the container to store the nodes with the required
29265  // number of segments
29266  tmp_segment_nodes.resize(nsegments);
29267 
29268  for (unsigned is = 0; is < nsegments; is++)
29269  {
29270 #ifdef PARANOID
29271  if (segment_sorted_ele_pt[is].size() == 0)
29272  {
29273  std::ostringstream error_message;
29274  error_message
29275  << "The (" << is << ")-th segment has no elements\n";
29276  throw OomphLibError(error_message.str(),
29277  "RefineableTriangleMesh::get_boundary_segment_nodes_helper()",
29278  OOMPH_EXCEPTION_LOCATION);
29279  } // if (segment_sorted_ele_pt[is].size() == 0)
29280 #endif
29281 
29282  // Get access to the first element on the segment
29283  FiniteElement* first_ele_pt = segment_sorted_ele_pt[is].front();
29284 
29285  // Number of nodes
29286  const unsigned nnod = first_ele_pt->nnode();
29287 
29288  // Get the first node of the current segment
29289  Node *first_node_pt = first_ele_pt->node_pt(0);
29290  if (is_inverted[first_ele_pt])
29291  {
29292  first_node_pt = first_ele_pt->node_pt(nnod-1);
29293  }
29294 
29295  // Add the node to the corresponding segment
29296  tmp_segment_nodes[is].push_back(first_node_pt);
29297 
29298  // Now loop over face elements in order to get the nodes
29299  for (std::list<FiniteElement*>::iterator it =
29300  segment_sorted_ele_pt[is].begin();
29301  it != segment_sorted_ele_pt[is].end(); it++)
29302  {
29303  // Get element
29304  FiniteElement* ele_pt = *it;
29305 
29306  // The last node pointer
29307  Node* last_node_pt = 0;
29308 
29309  // Get the last node
29310  if (!is_inverted[ele_pt])
29311  {
29312  last_node_pt = ele_pt->node_pt(nnod-1);
29313  }
29314  else
29315  {
29316  last_node_pt = ele_pt->node_pt(0);
29317  }
29318 
29319  // Add the node to the corresponding segment
29320  tmp_segment_nodes[is].push_back(last_node_pt);
29321 
29322  } // iterator over the elements in the segment
29323 
29324  } // for (is < nsegments)
29325 
29326  } // for (if (nel > 0))
29327 
29328  // Free memory allocation
29329  for (unsigned e = 0; e < nel; e++)
29330  {
29331  delete face_el_pt[e];
29332  face_el_pt[e] = 0;
29333  } // for (e < nel)
29334 
29335  }
29336 
29337 //======================================================================
29338 /// Adapt problem based on specified elemental error estimates
29339 /// This function implement serial and parallel mesh adaptation, the
29340 /// sections for parallel mesh adaptation are clearly identified by
29341 /// checking whether the mesh is distributed or not
29342 //======================================================================
29343  template <class ELEMENT>
29345  const Vector<double>& elem_error)
29346  {
29347  double t_start_overall=TimingHelpers::timer();
29348 
29349  // ==============================================================
29350  // BEGIN: Compute target areas
29351  // ==============================================================
29352 
29353  // Get refinement targets
29354  Vector<double> target_area(elem_error.size());
29355  double min_angle=compute_area_target(elem_error,
29356  target_area);
29357 
29358  // Post-process to allow only quantised target areas
29359  // in an attempt to more closely mimick the structured
29360  // case and limit the diffusion of small elements.
29361  bool quantised_areas=true;
29362  if (quantised_areas)
29363  {
29364  unsigned n=target_area.size();
29365  double total_area=0;
29366  // If the mesh is distributed then we need to get the contribution
29367  // of all processors to compute the total areas
29368  // ------------------------------------------
29369  // DISTRIBUTED MESH: BEGIN
29370  // ------------------------------------------
29371 #ifdef OOMPH_HAS_MPI
29372  if (this->is_mesh_distributed())
29373  {
29374  // When working in parallel we get the total area from the sum
29375  // of the the sub-areas of all the meshes
29376  double sub_area = 0.0;
29377 
29378  // Only add the area of nonhalo elements
29379  for (unsigned e=0;e<n;e++)
29380  {
29381  // Get the pointer to the element
29382  FiniteElement* ele_pt = this->finite_element_pt(e);
29383  if (!ele_pt->is_halo())
29384  {
29385  sub_area+=ele_pt->size();
29386  }
29387  } // for (e<n)
29388 
29389  // Get the communicator of the mesh
29390  OomphCommunicator* comm_pt = this->communicator_pt();
29391 
29392  // Get the total area
29393  MPI_Allreduce(&sub_area, &total_area, 1, MPI_DOUBLE, MPI_SUM,
29394  comm_pt->mpi_comm());
29395  }
29396  else
29397  {
29398  for (unsigned e=0;e<n;e++)
29399  {
29400  total_area+=this->finite_element_pt(e)->size();
29401  }
29402  }
29403  // ------------------------------------------
29404  // DISTRIBUTED MESH: END
29405  // ------------------------------------------
29406 #else // #ifdef OOMPH_HAS_MPI
29407  for (unsigned e=0;e<n;e++)
29408  {
29409  total_area+=this->finite_element_pt(e)->size();
29410  }
29411 #endif // #ifdef OOMPH_HAS_MPI
29412 
29413  for (unsigned e=0;e<n;e++)
29414  {
29415  unsigned level=
29416  unsigned(ceil(log(target_area[e]/total_area)/log(1.0/3.0)))-1;
29417  double new_target_area=total_area*pow(1.0/3.0,int(level));
29418  target_area[e]=new_target_area;
29419  }
29420 
29421  }
29422 
29423  // std::ofstream tmp;
29424  // tmp.open((Global_string_for_annotation:: String[0]+"overall_target_areas"+
29425  // StringConversion::to_string(Global_unsigned::Number)+".dat").c_str());
29426 
29427  // Get maximum target area
29428  unsigned n=target_area.size();
29429  double max_area=0.0;
29430  double min_area=DBL_MAX;
29431  for (unsigned e=0;e<n;e++)
29432  {
29433  if (target_area[e]>max_area) max_area=target_area[e];
29434  if (target_area[e]<min_area) min_area=target_area[e];
29435 
29436  // tmp << (finite_element_pt(e)->node_pt(0)->x(0)+
29437  // finite_element_pt(e)->node_pt(1)->x(0)+
29438  // finite_element_pt(e)->node_pt(2)->x(0))/3.0 << " "
29439  // << (finite_element_pt(e)->node_pt(0)->x(1)+
29440  // finite_element_pt(e)->node_pt(1)->x(1)+
29441  // finite_element_pt(e)->node_pt(2)->x(1))/3.0 << " "
29442  // << target_area[e] << " "
29443  // << finite_element_pt(e)->size() << " "
29444  // << elem_error[e] << " " << std::endl;
29445  }
29446 
29447  //tmp.close();
29448 
29449  oomph_info << "Maximum target area: " << max_area << std::endl;
29450  oomph_info << "Minimum target area: " << min_area << std::endl;
29451  oomph_info << "Number of elements to be refined: "
29452  << this->Nrefined << std::endl;
29453  oomph_info << "Number of elements to be unrefined: "
29454  << this->Nunrefined << std::endl;
29455  oomph_info << "Min. angle: " << min_angle << std::endl;
29456 
29457  double orig_max_area, orig_min_area;
29458  this->max_and_min_element_size(orig_max_area, orig_min_area);
29459  oomph_info << "Max./min. element size in original mesh: "
29460  << orig_max_area << " "
29461  << orig_min_area << std::endl;
29462 
29463  // ==============================================================
29464  // END: Compute target areas
29465  // ==============================================================
29466 
29467  // Check if boundaries need to be updated (regardless of
29468  // requirements of bulk error estimator) but don't do anything!
29469  bool check_only=true;
29470  bool outer_boundary_update_necessary= false;
29471  bool inner_boundary_update_necessary= false;
29472  bool inner_open_boundary_update_necessary=false;
29473 
29474  // Get the number of outer boundaries and check if they require
29475  // update
29476  const unsigned nouter=this->Outer_boundary_pt.size();
29477 
29478  if (this->is_automatic_creation_of_vertices_on_boundaries_allowed())
29479  {
29480  // loop over the outer boundaries
29481  for (unsigned i_outer = 0; i_outer < nouter; i_outer++)
29482  {
29483  outer_boundary_update_necessary=
29484  this->update_polygon_using_face_mesh(this->Outer_boundary_pt[i_outer],
29485  check_only);
29486  // Break the loop if at least one needs updating
29487  if (outer_boundary_update_necessary) break;
29488  }
29489 
29490  // Do not waste time if we already know that it is necessary an update
29491  // on the boundary representation
29492  if (!outer_boundary_update_necessary)
29493  {
29494  // Check if we need to generate a new 1D mesh representation of
29495  // the inner hole boundaries
29496  const unsigned nhole=this->Internal_polygon_pt.size();
29497  Vector<Vector<double> > internal_point_coord(nhole);
29498  inner_boundary_update_necessary=
29499  this->surface_remesh_for_inner_hole_boundaries(internal_point_coord,
29500  check_only);
29501 
29502  // If there was not necessary a change even on the internal closed
29503  // curve then finally check for the open curves as well
29504  if (!inner_boundary_update_necessary)
29505  {
29506  const unsigned n_open_polyline =
29507  this->Internal_open_curve_pt.size();
29508  // loop over the open polylines
29509  for (unsigned i = 0; i < n_open_polyline; i++)
29510  {
29511  inner_open_boundary_update_necessary=
29512  this->update_open_curve_using_face_mesh(
29513  this->Internal_open_curve_pt[i], check_only);
29514  // If at least one needs modification then break the for loop
29515  if (inner_open_boundary_update_necessary) break;
29516  }
29517  }
29518  }
29519  }
29520 
29521  // Flag to indicate whether we need to adapt or not (for parallel
29522  // mesh adaptation only)
29523  int adapt_all = 0;
29524  // ------------------------------------------
29525  // DISTRIBUTED MESH: BEGIN
29526  // ------------------------------------------
29527 #ifdef OOMPH_HAS_MPI
29528  // When working in distributed meshes we need to ensure that all the
29529  // processors take part on the adaptation process. If at least one
29530  // of the processors requires adaptation then all processor take
29531  // part on the adaptation process.
29532  int adapt_this_processor = 0;
29533  if (this->is_mesh_distributed())
29534  {
29535  // Do this processor requires adaptation?
29536  if ( (Nrefined > 0) || (Nunrefined > max_keep_unrefined()) ||
29537  (min_angle < min_permitted_angle())
29538  || (outer_boundary_update_necessary)
29539  || (inner_boundary_update_necessary)
29540  || (inner_open_boundary_update_necessary) )
29541  {adapt_this_processor = 1;}
29542 
29543  // Get the communicator of the mesh
29544  OomphCommunicator* comm_pt = this->communicator_pt();
29545 
29546  // Verify if at least one processor needs mesh adaptation
29547  MPI_Allreduce(&adapt_this_processor, &adapt_all, 1, MPI_INT, MPI_SUM,
29548  comm_pt->mpi_comm());
29549  }
29550 #endif
29551  // ------------------------------------------
29552  // DISTRIBUTED MESH: END
29553  // ------------------------------------------
29554 
29555  // Should we bother to adapt?
29556  if ( (Nrefined > 0) || (Nunrefined > max_keep_unrefined()) ||
29557  (min_angle < min_permitted_angle()) || (outer_boundary_update_necessary)
29558  || (inner_boundary_update_necessary)
29559  || (inner_open_boundary_update_necessary) || (adapt_all) )
29560  {
29561  if (! ( (Nrefined > 0) || (Nunrefined > max_keep_unrefined()) ) )
29562  {
29563 
29564  if ( (outer_boundary_update_necessary)
29565  || (inner_boundary_update_necessary)
29566  || (inner_open_boundary_update_necessary) )
29567  {
29568  oomph_info
29569  << "Mesh regeneration triggered by inaccurate interface/surface\n"
29570  << "representation; setting Nrefined to number of elements.\n"
29571  << "outer_boundary_update_necessary : "
29572  << outer_boundary_update_necessary << "\n"
29573  << "inner_boundary_update_necessary : "
29574  << inner_boundary_update_necessary << "\n"
29575  << "inner_open_boundary_update_necessary: "
29576  << inner_open_boundary_update_necessary << "\n";
29577  Nrefined=nelement();
29578  }
29579  else
29580  {
29581  oomph_info
29582  << "Mesh regeneration triggered by min angle criterion;\n"
29583  << "setting Nrefined to number of elements.\n";
29584  Nrefined=nelement();
29585  }
29586  }
29587 
29588  // ------------------------------------------
29589  // DISTRIBUTED MESH: BEGIN
29590  // ------------------------------------------
29591 #ifdef OOMPH_HAS_MPI
29592  else if (this->is_mesh_distributed() &&
29593  adapt_this_processor == 0 && adapt_all > 0)
29594  {
29595  oomph_info
29596  << "Mesh regeneration triggered by (" << adapt_all << ") processor(s) "
29597  << "that require(s)\n adaptation\n";
29598  }
29599 #endif
29600  // ------------------------------------------
29601  // DISTRIBUTED MESH: END
29602  // ------------------------------------------
29603 
29604  // ==============================================================
29605  // BEGIN: Updating of boundaries representation (unrefinement and
29606  // refinement of polylines)
29607  // ==============================================================
29608 
29609  // Add the initial and final vertices of the polylines that
29610  // present connections to a list of non-delete-able vertices. The
29611  // vertices where the connections are performed cannot be deleted
29612  add_vertices_for_non_deletion();
29613 
29614  // ------------------------------------------
29615  // DISTRIBUTED MESH: BEGIN
29616  // ------------------------------------------
29617 #ifdef OOMPH_HAS_MPI
29618  // Synchronise connections for shared boundaries among
29619  // processors. This is required since one of the processor may noy
29620  // know that some of its shared boundaries have connections, thus
29621  // the vertices receiving the connections cannot be deleted
29622  if (this->is_mesh_distributed())
29623  {
29624  synchronize_shared_boundary_connections();
29625  }
29626 #endif // #ifdef OOMPH_HAS_MPI
29627  // ------------------------------------------
29628  // DISTRIBUTED MESH: END
29629  // ------------------------------------------
29630 
29631  // Are we allowing automatic insertion of vertices on boundaries?
29632  // If YES then Triangle automatically insert points along
29633  // boundaries, if NOT, then points are inserted along the
29634  // boundaries based on the target areas of boundary elements. When
29635  // the mesh is distributed the automatic insertion of vertices by
29636  // Triangle along the boundaries is not allowed
29637  if (this->is_automatic_creation_of_vertices_on_boundaries_allowed())
29638  {
29639  //Generate a new 1D mesh representation of the inner hole boundaries
29640  unsigned nhole=this->Internal_polygon_pt.size();
29641  Vector<Vector<double> > internal_point_coord(nhole);
29642  this->surface_remesh_for_inner_hole_boundaries(internal_point_coord);
29643 
29644  //Update the representation of the outer boundary
29645  for (unsigned i_outer = 0; i_outer < nouter; i_outer++)
29646  {
29647  this->update_polygon_using_face_mesh(
29648  this->Outer_boundary_pt[i_outer]);
29649  }
29650 
29651  // After updating outer and internal closed boundaries it is also
29652  // necessary to update internal boundaries.
29653  unsigned n_open_polyline = this->Internal_open_curve_pt.size();
29654  for (unsigned i = 0; i < n_open_polyline; i++)
29655  {
29656  this->update_open_curve_using_face_mesh(
29657  this->Internal_open_curve_pt[i]);
29658  }
29659 
29660  }
29661  else
29662  {
29663  // Update the representation of the internal boundaries using
29664  // the element's target area
29665 
29666  // Get the number of interal polygons
29667  const unsigned ninternal=this->Internal_polygon_pt.size();
29668  for (unsigned i_internal = 0; i_internal < ninternal; i_internal++)
29669  {
29670  this->update_polygon_using_elements_area(
29671  this->Internal_polygon_pt[i_internal], target_area);
29672  }
29673 
29674  // Update the representation of the outer boundaries using the
29675  // element's target area
29676  for (unsigned i_outer = 0; i_outer < nouter; i_outer++)
29677  {
29678  this->update_polygon_using_elements_area(
29679  this->Outer_boundary_pt[i_outer], target_area);
29680  }
29681 
29682  // Update the representation of the internal open boundaries
29683  // using the element's target areas
29684  const unsigned n_open_polyline = this->Internal_open_curve_pt.size();
29685  for (unsigned i = 0; i < n_open_polyline; i++)
29686  {
29687  this->update_open_curve_using_elements_area(
29688  this->Internal_open_curve_pt[i], target_area);
29689  }
29690 
29691  // ------------------------------------------
29692  // DISTRIBUTED MESH: BEGIN
29693  // ------------------------------------------
29694 
29695  // When working with a distributed mesh we require to update the
29696  // boundary representation of the shared boundaries, this is
29697  // based on the target areas of the elements adjaced to the
29698  // shared boundaries
29699 #ifdef OOMPH_HAS_MPI
29700  // Update shared boundaries if the mesh is distributed
29701  if (this->is_mesh_distributed())
29702  {
29703  // Get the rank of the current processor
29704  const unsigned my_rank = this->communicator_pt()->my_rank();
29705 
29706  // Get the number of shared curves
29707  const unsigned n_curves = this->nshared_boundary_curves(my_rank);
29708  // Loop over the shared curves in the current processor
29709  for (unsigned nc = 0; nc < n_curves; nc ++)
29710  {
29711  // Update the shared polyline
29712  this->update_shared_curve_using_elements_area(
29713  this->Shared_boundary_polyline_pt[my_rank][nc],//shared_curve,
29714  target_area);
29715  }
29716 
29717  } // if (this->is_mesh_distributed())
29718 #endif
29719 
29720  // ------------------------------------------
29721  // DISTRIBUTED MESH: END
29722  // ------------------------------------------
29723 
29724  } // else if (this->is_automatic_creation_of_vertices_on_boundaries_allowed())
29725 
29726  // ==============================================================
29727  // END: Updating of boundaries representation (unrefinement and
29728  // refinement of polylines)
29729  // ==============================================================
29730 
29731  // ==============================================================
29732  // BEGIN: Reset boundary coordinates for boundaries with no
29733  // associated GeomObject
29734  // ==============================================================
29735 
29736  //If there is not a geometric object associated with the boundary
29737  //then reset the boundary coordinates so that the lengths are
29738  //consistent in the new mesh and the old mesh.
29739  const unsigned n_boundary = this->nboundary();
29740 
29741  const double t_start_first_stage_segments_connectivity =
29742  TimingHelpers::timer();
29743 
29744  // ------------------------------------------
29745  // DISTRIBUTED MESH: BEGIN
29746  // ------------------------------------------
29747 #ifdef OOMPH_HAS_MPI
29748  // Clear storage for assignment of initial zeta values for
29749  // boundaries
29750  if (this->is_mesh_distributed())
29751  {
29752  this->Assigned_segments_initial_zeta_values.clear();
29753  }
29754 #endif // #ifdef OOMPH_HAS_MPI
29755  // ------------------------------------------
29756  // DISTRIBUTED MESH: END
29757  // ------------------------------------------
29758 
29759  // Loop over the boundaries to assign boundary coordinates
29760  for(unsigned b=0;b<n_boundary;++b)
29761  {
29762  // ------------------------------------------
29763  // DISTRIBUTED MESH: BEGIN
29764  // ------------------------------------------
29765 #ifdef OOMPH_HAS_MPI
29766  if (this->is_mesh_distributed())
29767  {
29768  // In a distributed mesh, the boundaries may have been split
29769  // across processors during the distribution process, thus we
29770  // need to compute the connectivity among the segments of the
29771  // boundary to correctly assign its boundary coordinates
29772  this->
29773  compute_boundary_segments_connectivity_and_initial_zeta_values(b);
29774  }
29775 #endif
29776  // ------------------------------------------
29777  // DISTRIBUTED MESH: END
29778  // ------------------------------------------
29779 
29780  // Does the boundary has an associated GeomObject
29781  if(this->boundary_geom_object_pt(b)==0)
29782  {
29783  this->template setup_boundary_coordinates<ELEMENT>(b);
29784  }
29785 
29786  // ------------------------------------------
29787  // DISTRIBUTED MESH: BEGIN
29788  // ------------------------------------------
29789 #ifdef OOMPH_HAS_MPI
29790  if (this->is_mesh_distributed())
29791  {
29792  // Synchronise boundary coordinates for internal open curves,
29793  // also establish the boundary coordinates for the nodes on
29794  // the corners of elements not on the boundary
29795  this->synchronize_boundary_coordinates(b);
29796  }
29797 #endif
29798  // ------------------------------------------
29799  // DISTRIBUTED MESH: END
29800  // ------------------------------------------
29801 
29802  } // for (b<n_boundary)
29803 
29804  const double t_total_first_stage_segments_connectivity =
29805  TimingHelpers::timer() - t_start_first_stage_segments_connectivity;
29806 
29807  // ==============================================================
29808  // END: Reset boundary coordinates for boundaries with no
29809  // associated GeomObject
29810  // ==============================================================
29811 
29812  // ------------------------------------------
29813  // DISTRIBUTED MESH: BEGIN
29814  // ------------------------------------------
29815 #ifdef OOMPH_HAS_MPI
29816  // ==============================================================
29817  // BEGIN: Create the new representation of the domain by joining
29818  // the original boundaries and the shared boundaries.
29819  // ==============================================================
29820 
29821  // Storage for the new temporary polygons "closed" by the shared
29822  // boundaries
29823  Vector<TriangleMeshPolygon *> tmp_outer_polygons_pt;
29824 
29825  // Storage for the new temporary open curves, could be the
29826  // original open curves or "chunks" of the original open curves
29827  // not overlapped by shared boundaries
29828  Vector<TriangleMeshOpenCurve *> tmp_open_curves_pt;
29829 
29830  if (this->is_mesh_distributed())
29831  {
29832  // Create the new polygons and open curves with help of the
29833  // original polylines and shared polylines
29834  this->create_distributed_domain_representation(tmp_outer_polygons_pt,
29835  tmp_open_curves_pt);
29836 
29837  // Create the connections of the temporary domain representations
29838  this->create_temporary_boundary_connections(tmp_outer_polygons_pt,
29839  tmp_open_curves_pt);
29840  }
29841  // ==============================================================
29842  // END: Create the new representation of the domain by joining
29843  // the original boundaries and the shared boundaries.
29844  // ==============================================================
29845 #endif
29846  // ------------------------------------------
29847  // DISTRIBUTED MESH: END
29848  // ------------------------------------------
29849 
29850  // Re-establish polylines' connections. The boundary
29851  // representation has changed (new polylines), therefore we need
29852  // to update the connection information
29853  Vector<TriangleMeshPolyLine*> resume_initial_connection_polyline_pt;
29854  Vector<TriangleMeshPolyLine*> resume_final_connection_polyline_pt;
29855  restore_boundary_connections(resume_initial_connection_polyline_pt,
29856  resume_final_connection_polyline_pt);
29857 
29858  // Update the region information by setting the coordinates from the
29859  // centroid of the first element in each region (which should allow
29860  // automatic updates when the regions deform)
29861  {
29862  unsigned n_region = this->nregion();
29863  if(n_region > 1)
29864  {
29865  for(std::map<unsigned, Vector<double> >::iterator it =
29866  this->Regions_coordinates.begin();
29867  it!=this->Regions_coordinates.end(); ++it)
29868  {
29869  //Storage for the approximate centroid
29870  Vector<double> centroid(2,0.0);
29871 
29872  //Get the region id
29873  unsigned region_id = it->first;
29874 
29875  //Report information
29876  oomph_info << "Region " << region_id << ": "
29877  << it->second[0] << " " << it->second[1] << " ";
29878 
29879  //Check that there is at least one element in the region
29880  unsigned n_region_element = this->nregion_element(region_id);
29881  if(n_region_element > 0)
29882  {
29883  //Cache pointer to the first element
29884  FiniteElement* const elem_pt = this->region_element_pt(region_id,0);
29885 
29886  //Loop over the corners of the triangle and average
29887  for(unsigned n=0;n<3;n++)
29888  {
29889  Node* const nod_pt = elem_pt->node_pt(n);
29890  for(unsigned i=0;i<2;i++) {centroid[i] += nod_pt->x(i);}
29891  }
29892  for(unsigned i=0;i<2;i++) {centroid[i] /= 3;}
29893  //Now we have the centroid set it
29894  it->second = centroid;
29895 
29896  oomph_info << " , " <<
29897  it->second[0] << " " << it->second[1] << std::endl;
29898  } //end of case when there is at least one element
29899 
29900  } // loop over regions coordinates
29901 
29902  } // if(n_region > 1)
29903 
29904  } // Updating region info.
29905 
29906  // ==============================================================
29907  // BEGIN: Create background mesh
29908  // ==============================================================
29909 
29910  // Are we dealing with a solid mesh?
29911  SolidMesh* solid_mesh_pt=dynamic_cast<SolidMesh*>(this);
29912 
29913  // Build temporary uniform background mesh
29914  //----------------------------------------
29915  // with area set by maximum required area
29916  //---------------------------------------
29917  RefineableTriangleMesh<ELEMENT>* tmp_new_mesh_pt=0;
29918 
29919  // The storage for the new temporary boundaries representation to
29920  // create the background mesh
29921  Vector<TriangleMeshClosedCurve*> closed_curve_pt;
29922  Vector<TriangleMeshClosedCurve*> hole_pt;
29923  Vector<TriangleMeshOpenCurve*> open_curves_pt;
29924 
29925 #ifdef OOMPH_HAS_MPI
29926  if (!this->is_mesh_distributed())
29927 #endif
29928  {
29929  // Copy the outer boundaries
29930  closed_curve_pt.resize(nouter);
29931  for (unsigned i = 0; i < nouter; i++)
29932  {
29933  closed_curve_pt[i] = this->Outer_boundary_pt[i];
29934  }
29935 
29936  // Copy the internal closed boundaries (may be holes)
29937  const unsigned n_holes = this->Internal_polygon_pt.size();
29938  hole_pt.resize(n_holes);
29939  for (unsigned i = 0; i < n_holes; i++)
29940  {
29941  hole_pt[i] = this->Internal_polygon_pt[i];
29942  }
29943 
29944  // Copy the internal open curves
29945  const unsigned n_open_curves = this->Internal_open_curve_pt.size();
29946  open_curves_pt.resize(n_open_curves);
29947  for (unsigned i = 0; i < n_open_curves; i++)
29948  {
29949  open_curves_pt[i] = this->Internal_open_curve_pt[i];
29950  }
29951  }
29952  // ------------------------------------------
29953  // DISTRIBUTED MESH: BEGIN
29954  // ------------------------------------------
29955 #ifdef OOMPH_HAS_MPI
29956  else
29957  {
29958  // Copy the new representation of the outer/internal closed
29959  // boundaries
29960  const unsigned n_tmp_outer = tmp_outer_polygons_pt.size();
29961  closed_curve_pt.resize(n_tmp_outer);
29962  for (unsigned i = 0; i < n_tmp_outer; i++)
29963  {
29964  closed_curve_pt[i] = tmp_outer_polygons_pt[i];
29965  }
29966 
29967  // Copy the new representation of the internal open curves
29968  const unsigned n_open_curves = tmp_open_curves_pt.size();
29969  open_curves_pt.resize(n_open_curves);
29970  for (unsigned i = 0; i < n_open_curves; i++)
29971  {
29972  open_curves_pt[i] = tmp_open_curves_pt[i];
29973  }
29974 
29975  }
29976 #endif
29977  // ------------------------------------------
29978  // DISTRIBUTED MESH: END
29979  // ------------------------------------------
29980 
29981  // ----------------------------------------------------------------
29982  // Gather all the information and use the TriangleMeshParameters
29983  // object which help us on the manage of all TriangleMesh object's
29984  // information
29985 
29986  // Create the TriangleMeshParameters objects with the outer boundary
29987  // as the only one parameter
29988  TriangleMeshParameters triangle_mesh_parameters(closed_curve_pt);
29989 
29990  // Pass information about the holes
29991  triangle_mesh_parameters.internal_closed_curve_pt() = hole_pt;
29992 
29993  // Pass information about the internal open boundaries
29994  triangle_mesh_parameters.internal_open_curves_pt() = open_curves_pt;
29995 
29996  // Set the element area
29997  triangle_mesh_parameters.element_area() = max_area;
29998 
29999  // Pass information about the extra holes (not defined with closed
30000  // boundaries)
30001  triangle_mesh_parameters.extra_holes_coordinates() =
30002  this->Extra_holes_coordinates;
30003 
30004  //Pass information about regions
30005  triangle_mesh_parameters.regions_coordinates() =
30006  this->Regions_coordinates;
30007 
30008  //Pass information about the using of regions
30009  if (this->Use_attributes)
30010  {
30011  triangle_mesh_parameters.enable_use_attributes();
30012  }
30013 
30014  //Pass information about allowing the creation of new points
30015  if (!this->is_automatic_creation_of_vertices_on_boundaries_allowed())
30016  {
30017  triangle_mesh_parameters.disable_automatic_creation_of_vertices_on_boundaries();
30018  }
30019 
30020  // When the mesh is distributed we need to create a distributed
30021  // background mesh
30022 #ifdef OOMPH_HAS_MPI
30023  if (this->is_mesh_distributed())
30024  {
30025  // Mark the mesh to be created as distributed by passing a
30026  // pointer to the communicator
30027  triangle_mesh_parameters.set_communicator_pt(this->communicator_pt());
30028  }
30029 #endif
30030 
30031  // ----------------------------------------------------------
30032  // Build the background mesh using Triangle
30033  // ----------------------------------------------------------
30034  const double t_start_building_background_mesh =
30035  TimingHelpers::timer();
30036 
30037  if (solid_mesh_pt!=0)
30038  {
30039  tmp_new_mesh_pt=new RefineableSolidTriangleMesh<ELEMENT>
30040  (triangle_mesh_parameters, this->Time_stepper_pt);
30041  }
30042  else
30043  {
30044  tmp_new_mesh_pt=new RefineableTriangleMesh<ELEMENT>
30045  (triangle_mesh_parameters, this->Time_stepper_pt);
30046  }
30047 
30048  if (Print_timings_level_adaptation>2)
30049  {
30050  oomph_info << "CPU for building background mesh: "
30051  <<TimingHelpers::timer()-t_start_building_background_mesh
30052  << std::endl;
30053  }
30054 
30055  // Pass the info. regarding the maximum and minimum element size
30056  // from the old mesh to the background mesh
30057  const double this_max_element_size = this->max_element_size();
30058  const double this_min_element_size = this->min_element_size();
30059  tmp_new_mesh_pt->max_element_size() = this_max_element_size;
30060  tmp_new_mesh_pt->min_element_size() = this_min_element_size;
30061 
30062  // ... also copy the minimum permitted angle
30063  const double this_min_permitted_angle = this->min_permitted_angle();
30064  tmp_new_mesh_pt->min_permitted_angle() = this_min_permitted_angle;
30065 
30066  // ------------------------------------------
30067  // DISTRIBUTED MESH: BEGIN
30068  // ------------------------------------------
30069 #ifdef OOMPH_HAS_MPI
30070  // If the mesh is distributed we need to pass and set the
30071  // information of internal boundaries overlaped by shared
30072  // boundaries
30073  if (this->is_mesh_distributed())
30074  {
30075  // Check if necessary to fill boundary elements for those
30076  // internal boundaries that overlap shared boundaries
30077  if (this->nshared_boundary_overlaps_internal_boundary() > 0)
30078  {
30079  // Copy the data structures that indicates which shared
30080  // boundaries are part of an internal boundary
30081  tmp_new_mesh_pt->shared_boundary_overlaps_internal_boundary() =
30082  this->shared_boundary_overlaps_internal_boundary();
30083 
30084  // Copy the data structure that indicates which are the shared
30085  // boundaries in each processor
30086  tmp_new_mesh_pt->shared_boundaries_ids() =
30087  this->shared_boundaries_ids();
30088 
30089  // Fill the structures for the boundary elements and face indexes
30090  // of the boundary elements
30091  tmp_new_mesh_pt->
30092  fill_boundary_elements_and_nodes_for_internal_boundaries();
30093 
30094  } // if (this->nshared_boundary_overlaps_internal_boundary() > 0)
30095 
30096  } // if (this->is_mesh_distributed())
30097 #endif // #ifdef OOMPH_HAS_MPI
30098  // ------------------------------------------
30099  // DISTRIBUTED MESH: END
30100  // ------------------------------------------
30101 
30102  // Snap to curvilinear boundaries (some code duplication as this
30103  // is repeated below but helper function would take so many
30104  // arguments that it's nearly as messy...
30105 
30106  //Pass the boundary geometric objects to the new mesh
30107  tmp_new_mesh_pt->boundary_geom_object_pt() =
30108  this->boundary_geom_object_pt();
30109 
30110  //Reset the boundary coordinates if there is
30111  //a geometric object associated with the boundary
30112  tmp_new_mesh_pt->boundary_coordinate_limits() =
30113  this->boundary_coordinate_limits();
30114 
30115  const double t_start_second_stage_segments_connectivity =
30116  TimingHelpers::timer();
30117 
30118  for (unsigned b=0;b<n_boundary;b++)
30119  {
30120  // ------------------------------------------
30121  // DISTRIBUTED MESH: BEGIN
30122  // ------------------------------------------
30123 #ifdef OOMPH_HAS_MPI
30124  if (this->is_mesh_distributed())
30125  {
30126  // Identify the segments of the new mesh with the ones of the
30127  // original mesh
30128  tmp_new_mesh_pt->
30129  identify_boundary_segments_and_assign_initial_zeta_values(b,this);
30130  }
30131 #endif
30132  // ------------------------------------------
30133  // DISTRIBUTED MESH: END
30134  // ------------------------------------------
30135 
30136  // Setup boundary coordinates for boundaries with GeomObject
30137  // associated
30138  if(tmp_new_mesh_pt->boundary_geom_object_pt(b)!=0)
30139  {
30140  tmp_new_mesh_pt->template setup_boundary_coordinates<ELEMENT>(b);
30141  }
30142 
30143  }
30144 
30145  const double t_total_second_stage_segments_connectivity =
30146  TimingHelpers::timer() - t_start_second_stage_segments_connectivity;
30147 
30148  const double t_start_snap_nodes_bg_mesh=TimingHelpers::timer();
30149  //Move the nodes on the new boundary onto the old curvilinear
30150  //boundary. If the boundary is straight this will do precisely
30151  //nothing but will be somewhat inefficient
30152  for(unsigned b=0;b<n_boundary;b++)
30153  {
30154  this->snap_nodes_onto_boundary(tmp_new_mesh_pt,b);
30155  }
30156 
30157  const double t_total_snap_nodes_bg_mesh=
30158  TimingHelpers::timer()-t_start_snap_nodes_bg_mesh;
30159 
30160  if (Print_timings_level_adaptation>2)
30161  {
30162  oomph_info<< "CPU for snapping nodes onto boundaries "
30163  << "(background mesh): "
30164  << t_total_snap_nodes_bg_mesh << std::endl;
30165  }
30166 
30167  // Update mesh further?
30168  if(Mesh_update_fct_pt!=0)
30169  {
30170  Mesh_update_fct_pt(tmp_new_mesh_pt);
30171  }
30172 
30173  //If we have a continuation problem
30174  //any problem in which the timestepper is a "generalisedtimestepper",
30175  //which will have been set by the problem, then ensure
30176  //all data in the new mesh has the appropriate timestepper
30177  /*if(dynamic_cast<GeneralisedTimeStepper*>(this->Time_stepper_pt))
30178  {
30179  tmp_new_mesh_pt->set_nodal_and_elemental_time_stepper(
30180  this->Time_stepper_pt);
30181  tmp_new_mesh_pt->set_mesh_level_time_stepper(this->Time_stepper_pt);
30182  }*/
30183 
30184 
30185  //tmp_new_mesh_pt->output("mesh_nodes_snapped_0.dat");
30186  //this->output("existing_mesh.dat");
30187 
30188  // ==============================================================
30189  // END: Create background mesh
30190  // ==============================================================
30191 
30192  // ==============================================================
30193  // BEGIN: Transferring of target areas and creation of new mesh
30194  // ==============================================================
30195 
30196  // Get the TriangulateIO object associated with that mesh
30197  TriangulateIO tmp_new_triangulateio =
30198  tmp_new_mesh_pt->triangulateio_representation();
30199  RefineableTriangleMesh<ELEMENT>* new_mesh_pt = 0;
30200 
30201  // If the mesh is a solid mesh then do the mapping based on the
30202  // Eulerian coordinates
30203  bool use_eulerian_coords=false;
30204  if (solid_mesh_pt!=0)
30205  {
30206  use_eulerian_coords=true;
30207  }
30208 
30209 
30210 #ifdef OOMPH_HAS_CGAL
30211 
30212  // Make cgal-based bin
30213  CGALSamplePointContainerParameters cgal_params(this);
30214  if (use_eulerian_coords)
30215  {
30216  cgal_params.enable_use_eulerian_coordinates_during_setup();
30217  }
30218  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(&cgal_params);
30219 
30220 #else
30221 
30222  // Make nonrefineable bin
30223  NonRefineableBinArrayParameters params(this);
30224  if (use_eulerian_coords)
30225  {
30226  params.enable_use_eulerian_coordinates_during_setup();
30227  }
30228  Vector<unsigned> bin_dim(2);
30229  bin_dim[0]=Nbin_x_for_area_transfer;
30230  bin_dim[1]=Nbin_y_for_area_transfer;
30231  params.dimensions_of_bin_array()=bin_dim;
30232  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(&params);
30233 
30234 #endif
30235 
30236  // Set up a map from pointer to element to its number
30237  // in the mesh
30238  std::map<GeneralisedElement*,unsigned> element_number;
30239  unsigned nelem=this->nelement();
30240  for (unsigned e=0;e<nelem;e++)
30241  {
30242  element_number[this->element_pt(e)]=e;
30243  }
30244 
30245 #ifndef OOMPH_HAS_CGAL
30246 
30247  // Create a vector to store the min target area of each bin (at
30248  // this stage the number of bins should not be that large, so it
30249  // should be safe to build a vector for the total number of bins)
30250  Vector<double> bin_min_target_area;
30251 
30252  // Get pointer to sample point container
30253  NonRefineableBinArray* bin_array_pt=
30254  dynamic_cast<NonRefineableBinArray*>(mesh_geom_obj_pt->
30255  sample_point_container_pt());
30256  if (bin_array_pt==0)
30257  {
30258  throw OomphLibError(
30259  "Sample point container has to be NonRefineableBinArray",
30260  OOMPH_CURRENT_FUNCTION,
30261  OOMPH_EXCEPTION_LOCATION);
30262  }
30263 
30264  {
30265  unsigned n_bin=0;
30266  unsigned max_n_entry=0;
30267  unsigned min_n_entry=UINT_MAX;
30268  unsigned tot_n_entry=0;
30269  unsigned n_empty=0;
30270  bin_array_pt->get_fill_stats(n_bin,max_n_entry,min_n_entry,
30271  tot_n_entry,n_empty);
30272 
30273  oomph_info << "Before bin diffusion:"
30274  << " nbin:("<<n_bin<<")"
30275  << " nempty:("<<n_empty<<")"
30276  << " min:("<<min_n_entry<<")"
30277  << " max:("<<max_n_entry<<")"
30278  << " average entries:("
30279  << double(tot_n_entry)/double(n_bin)<<")"
30280  << std::endl;
30281  }
30282 
30283  // Fill bin by diffusion
30284  double t0_bin_diff=TimingHelpers::timer();
30285  oomph_info << "Going into diffusion bit...\n";
30286  bin_array_pt->fill_bin_by_diffusion();
30287  oomph_info << "Back from diffusion bit...\n";
30288  oomph_info << "Time for bin diffusion: "
30289  << TimingHelpers::timer()-t0_bin_diff
30290  << std::endl;
30291 
30292  // Do some stats
30293  {
30294  unsigned n_bin=0;
30295  unsigned max_n_entry=0;
30296  unsigned min_n_entry=UINT_MAX;
30297  unsigned tot_n_entry=0;
30298  unsigned n_empty=0;
30299  bin_array_pt->get_fill_stats(n_bin,max_n_entry,min_n_entry,
30300  tot_n_entry,n_empty);
30301 
30302  oomph_info << "After bin diffusion:"
30303  << " nbin:("<<n_bin<<")"
30304  << " nempty:("<<n_empty<<")"
30305  << " min:("<<min_n_entry<<")"
30306  << " max:("<<max_n_entry<<")"
30307  << " average entries:("
30308  << double(tot_n_entry)/double(n_bin)<<")"
30309  << std::endl;
30310  }
30311 
30312 
30313  // For each bin, compute the minimum of the target areas in the bin
30314 
30315  // Timing for map
30316  double t_total_map=0.0;
30317 
30318  // Counter for map
30319  unsigned counter_map = 0;
30320 
30321  // Get access to the bins (we need access to the content of the
30322  // bins to compute the minimum of the target areas of the elements
30323  // in each bin)
30324  const std::map<unsigned,Vector<std::pair<FiniteElement*,
30325  Vector<double> > > >*
30326  bins_pt=bin_array_pt->get_all_bins_content();
30327 
30328  // Get the number of bins
30329  const unsigned n_bin=bins_pt->size();
30330 
30331  // Create a vector to store the min target area of each bin (at
30332  // this stage the number of bins should not be that large, so it
30333  // should be safe to build a vector for the total number of bins)
30334  bin_min_target_area.resize(n_bin);
30335  for (unsigned u=0;u<n_bin;u++)
30336  {
30337  bin_min_target_area[u]=0.0;
30338  }
30339  // loop over the bins, get their elements and compute the minimum
30340  // target area of all of them
30341  typedef std::map<unsigned,
30342  Vector<std::pair<FiniteElement*,
30343  Vector<double> > > >::const_iterator IT;
30344  for (IT it=bins_pt->begin();it!=bins_pt->end();it++)
30345  {
30346  // The bin number
30347  unsigned ib=(*it).first;
30348 
30349  // Get the number of elements in the bin
30350  const unsigned n_ele_bin = (*it).second.size();
30351 
30352  // loop over the elements in the bin
30353  for (unsigned ee=0;ee<n_ele_bin;ee++)
30354  {
30355  // Get ee-th element (in currrent mesh) in ib-th bin
30356  GeneralisedElement* ele_pt=(*it).second[ee].first;
30357  double t_map=TimingHelpers::timer();
30358  const unsigned ele_number = element_number[ele_pt];
30359  t_total_map+=TimingHelpers::timer()-t_map;
30360 
30361  // Increase the number of calls to map
30362  counter_map++;
30363 
30364  // Go for smallest target area of any element in this bin to
30365  // force "one level" of refinement (the one-level-ness is
30366  // enforced below by limiting the actual reduction in area
30367  if (bin_min_target_area[ib]!=0)
30368  {
30369  bin_min_target_area[ib]=
30370  std::min(bin_min_target_area[ib], target_area[ele_number]);
30371  }
30372  else
30373  {
30374  bin_min_target_area[ib]=target_area[ele_number];
30375  }
30376 
30377  } // for (ee<n_ele_bin)
30378 
30379  } // for (it!=bins.end())
30380 
30381  oomph_info << "CPU for map[counter="<<counter_map<<"]: "
30382  << t_total_map << std::endl;
30383 
30384 
30385  // Optional output for debugging (keep it around!)
30386  const bool output_bins=false;
30387  if (output_bins)
30388  {
30389  unsigned length=bin_min_target_area.size();
30390  for (unsigned u = 0;u<length;u++)
30391  {
30392  oomph_info << "Bin n" << u << ",target area: "
30393  << bin_min_target_area[u]<<std::endl;
30394  }
30395  }
30396 
30397 #endif
30398 
30399 
30400  // Now start iterating to refine mesh recursively
30401  //-----------------------------------------------
30402  bool done=false;
30403  unsigned iter=0;
30404 #ifdef OOMPH_HAS_MPI
30405  // The number of elements that require (un)refinement
30406  unsigned n_ele_need_refinement = 0;
30407 #endif
30408 
30409  // The timing for the third stage of segments connectivity
30410  double t_total_third_stage_segments_connectivity = 0.0;
30411 
30412  // The timing for the transfering target areas
30413  double t_total_transfer_target_areas = 0.0;
30414 
30415  // The timing for the copying of target areas
30416  double t_total_limit_target_areas = 0.0;
30417 
30418  // The timing to create the new mesh
30419  double t_total_create_new_adapted_mesh = 0.0;
30420 
30421  // The timing for the snapping of the nodes on the new meshes
30422  double t_total_snap_nodes = 0.0;
30423 
30424  // The timing to check whether other processors need to adapt
30425  double t_total_wait_other_processors = 0.0;
30426  double t_iter=TimingHelpers::timer();
30427  while (!done)
30428  {
30429  // Accept by default but overwrite if things go wrong below
30430  done=true;
30431 
30432  double t_start_transfer_target_areas=TimingHelpers::timer();
30433  double t0_loop_int_pts=TimingHelpers::timer();
30434 
30435  // Loop over elements in new (tmp) mesh and visit all
30436  // its integration points. Check where it's located in the bin
30437  // structure of the current mesh and pass the target area
30438  // to the new element
30439  nelem=tmp_new_mesh_pt->nelement();
30440 
30441  // Store the target areas for elements in the temporary
30442  // TriangulateIO mesh
30443  Vector<double> new_transferred_target_area(nelem,0.0);
30444  for (unsigned e=0;e<nelem;e++)
30445  { // start loop el
30446  ELEMENT* el_pt=dynamic_cast<ELEMENT*>(tmp_new_mesh_pt->element_pt(e));
30447  unsigned nint=el_pt->integral_pt()->nweight();
30448  for (unsigned ipt=0;ipt<nint;ipt++)
30449  {
30450  // Get the coordinate of current point
30451  Vector<double> s(2);
30452  for(unsigned i=0;i<2;i++)
30453  {
30454  s[i] = el_pt->integral_pt()->knot(ipt,i);
30455  }
30456 
30457  Vector<double> x(2);
30458  el_pt->interpolated_x(s,x);
30459 
30460 #if OOMPH_HAS_CGAL
30461 
30462  // Try the five nearest sample points for Newton search
30463  // then just settle on the nearest one
30464  GeomObject* geom_obj_pt=0;
30465  unsigned max_sample_points=
30466  Max_sample_points_for_limited_locate_zeta_during_target_area_transfer;
30467  dynamic_cast<CGALSamplePointContainer*>(mesh_geom_obj_pt->
30468  sample_point_container_pt())->
30469  limited_locate_zeta(x,max_sample_points,
30470  geom_obj_pt,s);
30471 #ifdef PARANOID
30472  if (geom_obj_pt==0)
30473  {
30474  std::stringstream error_message;
30475  error_message
30476  << "Limited locate zeta failed for zeta = [ "
30477  << x[0] << " " << x[1] << " ]. Makes no sense!\n";
30478  throw OomphLibError(error_message.str(),
30479  OOMPH_CURRENT_FUNCTION,
30480  OOMPH_EXCEPTION_LOCATION);
30481  }
30482  else
30483  {
30484 #endif
30485  FiniteElement* fe_pt=dynamic_cast<FiniteElement*>(geom_obj_pt);
30486 #ifdef PARANOID
30487  if (fe_pt==0)
30488  {
30489  std::stringstream error_message;
30490  error_message
30491  << "Cast to FE for GeomObject returned by limited locate zeta failed for zeta = [ "
30492  << x[0] << " " << x[1] << " ]. Makes no sense!\n";
30493  throw OomphLibError(error_message.str(),
30494  OOMPH_CURRENT_FUNCTION,
30495  OOMPH_EXCEPTION_LOCATION);
30496  }
30497  else
30498  {
30499 #endif
30500  // What's the target area of the element that contains this point
30501  double tg_area=target_area[element_number[fe_pt]];
30502 
30503  // Go for smallest target area over all integration
30504  // points in new element
30505  // to force "one level" of refinement (the one-level-ness
30506  // is enforced below by limiting the actual reduction in
30507  // area
30508  if (new_transferred_target_area[e]!=0)
30509  {
30510  new_transferred_target_area[e]=
30511  std::min(new_transferred_target_area[e],
30512  tg_area);
30513  }
30514  else
30515  {
30516  new_transferred_target_area[e]=tg_area;
30517  }
30518 #ifdef PARANOID
30519  }
30520  }
30521 #endif
30522 
30523 #else
30524 
30525  // Find the bin that contains that point and its contents
30526  int bin_number=0;
30527  bin_array_pt->get_bin(x,bin_number);
30528 
30529  // Did we find it?
30530  if (bin_number<0)
30531  {
30532  // Not even within bin boundaries... odd
30533  std::stringstream error_message;
30534  error_message
30535  << "Very odd -- we're looking for a point[ "
30536  << x[0] << " " << x[1] << " ] that's not even \n"
30537  << "located within the bin boundaries.\n";
30538  throw OomphLibError(error_message.str(),
30539  "RefineableTriangleMesh::adapt()",
30540  OOMPH_EXCEPTION_LOCATION);
30541  } // if (bin_number<0)
30542  else
30543  {
30544  // Go for smallest target area of any element in this bin
30545  // to force "one level" of refinement (the one-level-ness
30546  // is enforced below by limiting the actual reduction in
30547  // area
30548  if (new_transferred_target_area[e]!=0)
30549  {
30550  new_transferred_target_area[e]=
30551  std::min(new_transferred_target_area[e],
30552  bin_min_target_area[bin_number]);
30553  }
30554  else
30555  {
30556  new_transferred_target_area[e]=bin_min_target_area[bin_number];
30557  }
30558 
30559  }
30560 
30561 #endif
30562 
30563  } // for (ipt<nint)
30564 
30565  } // for (e<nelem)
30566 
30567 
30568  // do some output (keep it alive!)
30569  const bool output_target_areas=false;
30570  if (output_target_areas)
30571  {
30572  unsigned length=new_transferred_target_area.size();
30573  for (unsigned u = 0; u < length;u++)
30574  {
30575  oomph_info << "Element" << u << ",target area: "
30576  << new_transferred_target_area[u] << std::endl;
30577  }
30578  }
30579  oomph_info << "Time for loop over integration points in new mesh: "
30580  << TimingHelpers::timer()-t0_loop_int_pts
30581  << std::endl;
30582 
30583 
30584  // {
30585  // tmp.open((Global_string_for_annotation:: String[0]+"binned_target_areas"+
30586  // StringConversion::to_string(Global_unsigned::Number)+".dat").c_str());
30587 
30588  // Vector<Vector<std::pair<FiniteElement*,Vector<double> > > > bin_content=
30589  // mesh_geom_obj_pt->bin_content();
30590  // unsigned nbin=bin_content.size();
30591  // for (unsigned b=0;b<nbin;b++)
30592  // {
30593  // unsigned nentry=bin_content[b].size();
30594  // for (unsigned entry=0;entry<nentry;entry++)
30595  // {
30596  // FiniteElement* el_pt=bin_content[b][entry].first;
30597  // GeneralisedElement* gen_el_pt=bin_content[b][entry].first;
30598  // Vector<double> s=bin_content[b][entry].second;
30599  // Vector<double> x(2);
30600  // el_pt->interpolated_x(s,x);
30601  // unsigned e_current=element_number[gen_el_pt];
30602  // tmp << x[0] << " " << x[1] << " "
30603  // << target_area[e_current] << " "
30604  // << el_pt->size() << " "
30605  // << std::endl;
30606  // }
30607  // }
30608  // tmp.close();
30609  // }
30610 
30611  const double t_sub_total_transfer_target_areas =
30612  TimingHelpers::timer()-t_start_transfer_target_areas;
30613 
30614  if (Print_timings_level_adaptation>2)
30615  {
30616  // Get the number of elements in the old mesh (this)
30617  const unsigned n_element = this->nelement();
30618  // Get the number of elements in the background mesh
30619  const unsigned n_element_background = tmp_new_mesh_pt->nelement();
30620 
30621  oomph_info << "CPU for transfer of target areas "
30622  << "[n_ele_old_mesh="
30623  << n_element <<", n_ele_background_mesh="
30624  << n_element_background<<"] (iter "<< iter << "): "
30625  << t_sub_total_transfer_target_areas<< std::endl;
30626  }
30627 
30628  // Add the timing for tranfer of target areas
30629  t_total_transfer_target_areas+=t_sub_total_transfer_target_areas;
30630 
30631  // // Output mesh
30632  // tmp_new_mesh_pt->output(("intermediate_mesh"+
30633  // StringConversion::to_string(iter)+".dat").c_str());
30634 
30635  // tmp.open((Global_string_for_annotation:: String[0]+"target_areas_intermediate_mesh_iter"+
30636  // StringConversion::to_string(iter)+"_"+
30637  // StringConversion::to_string(Global_unsigned::Number)+".dat").c_str());
30638 
30639  const double t_start_limit_target_areas = TimingHelpers::timer();
30640 
30641  // Now copy into target area for temporary mesh but limit to
30642  // the equivalent of one sub-division per iteration
30643 #ifdef OOMPH_HAS_MPI
30644  unsigned n_ele_need_refinement_iter = 0;
30645 #endif
30646 
30647 
30648  // Don't delete! Keep these around for debugging
30649  // ofstream tmp_mesh_file;
30650  // tmp_mesh_file.open("tmp_mesh_file.dat");
30651  // tmp_new_mesh_pt->output(tmp_mesh_file);
30652  // tmp_mesh_file.close();
30653  // ofstream target_areas_file;
30654  // target_areas_file.open("target_areas_file.dat");
30655 
30656  const unsigned nel_new=tmp_new_mesh_pt->nelement();
30657  Vector<double> new_target_area(nel_new);
30658  for (unsigned e=0;e<nel_new;e++)
30659  {
30660  // The finite element
30661  FiniteElement* f_ele_pt = tmp_new_mesh_pt->finite_element_pt(e);
30662 
30663  // Transferred target area
30664  const double new_area=new_transferred_target_area[e];
30665  if (new_area<=0.0)
30666  {
30667  std::ostringstream error_stream;
30668  error_stream << "This shouldn't happen! Element whose centroid is at "
30669  << (f_ele_pt->node_pt(0)->x(0)+
30670  f_ele_pt->node_pt(1)->x(0)+
30671  f_ele_pt->node_pt(2)->x(0))/3.0 << " "
30672  << (f_ele_pt->node_pt(0)->x(1)+
30673  f_ele_pt->node_pt(1)->x(1)+
30674  f_ele_pt->node_pt(2)->x(1))/3.0 << " "
30675  << " has no target area assigned\n";
30676  throw OomphLibError(error_stream.str(),
30677  OOMPH_CURRENT_FUNCTION,
30678  OOMPH_EXCEPTION_LOCATION);
30679  }
30680  else
30681  {
30682 
30683 
30684  // Limit target area to the equivalent of uniform refinement
30685  // during this stage of the iteration
30686  new_target_area[e]=new_area;
30687  if (new_target_area[e]<f_ele_pt->size()/3.0)
30688  {
30689  new_target_area[e]=f_ele_pt->size()/3.0;
30690 
30691  // We'll need to give it another go later
30692  done=false;
30693 
30694  }
30695 
30696  // Don't delete! Keep around for debugging
30697  // target_areas_file
30698  // << (f_ele_pt->node_pt(0)->x(0)+
30699  // f_ele_pt->node_pt(1)->x(0)+
30700  // f_ele_pt->node_pt(2)->x(0))/3.0 << " "
30701  // << (f_ele_pt->node_pt(0)->x(1)+
30702  // f_ele_pt->node_pt(1)->x(1)+
30703  // f_ele_pt->node_pt(2)->x(1))/3.0 << " "
30704  // << new_area << " "
30705  // << new_target_area[e] << std::endl;
30706 
30707 
30708 
30709 #ifdef OOMPH_HAS_MPI
30710  // Keep track of the elements that require (un)refinement
30711  n_ele_need_refinement_iter++;
30712 #endif
30713 
30714  } // else if (new_area <= 0.0)
30715 
30716  } // for (e < nel_new)
30717 
30718 
30719  // Don't delete! Keep around for debugging
30720  // target_areas_file.close();
30721 
30722  const double t_sub_total_limit_target_areas =
30723  TimingHelpers::timer() - t_start_limit_target_areas;
30724 
30725  // Add the timing for copying target areas
30726  t_total_limit_target_areas+=t_sub_total_limit_target_areas;
30727 
30728  if (Print_timings_level_adaptation>2)
30729  {
30730  // Get the number of elements in the old mesh (this)
30731  const unsigned n_element = this->nelement();
30732  // Get the number of elements in the background mesh
30733  const unsigned n_element_background = tmp_new_mesh_pt->nelement();
30734 
30735  oomph_info << "CPU for limiting target areas "
30736  << "[n_ele_old_mesh="
30737  << n_element <<", n_ele_background_mesh="
30738  << n_element_background<<"] (iter "<< iter << "): "
30739  << t_sub_total_limit_target_areas<< std::endl;
30740  }
30741 
30742  if (done)
30743  {
30744  oomph_info
30745  << "All area adjustments accommodated by max. permitted area"
30746  << " reduction \n";
30747  }
30748  else
30749  {
30750  oomph_info
30751  << "NOT all area adjustments accommodated by max. "
30752  << "permitted area reduction \n";
30753  }
30754 
30755  //tmp.close();
30756  //pause("doced binned_target_areas.dat and intermediate mesh targets");
30757 
30758  // Now create the new mesh from TriangulateIO structure
30759  //-----------------------------------------------------
30760  // associated with uniform background mesh and the
30761  //------------------------------------------------
30762  // associated target element sizes.
30763  //---------------------------------
30764 
30765  const double t_start_create_new_adapted_mesh =
30766  TimingHelpers::timer();
30767 
30768  // Solid mesh?
30769  if (solid_mesh_pt!=0)
30770  {
30771  new_mesh_pt=new RefineableSolidTriangleMesh<ELEMENT>
30772  (new_target_area,
30773  tmp_new_triangulateio,
30774  this->Time_stepper_pt,
30775  this->Use_attributes,
30776  this->Allow_automatic_creation_of_vertices_on_boundaries,
30777  this->communicator_pt());
30778  }
30779  // No solid mesh
30780  else
30781  {
30782  new_mesh_pt=new RefineableTriangleMesh<ELEMENT>
30783  (new_target_area,
30784  tmp_new_triangulateio,
30785  this->Time_stepper_pt,
30786  this->Use_attributes,
30787  this->Allow_automatic_creation_of_vertices_on_boundaries,
30788  this->communicator_pt());
30789  }
30790 
30791  // Sub-total to create new adapted mesh
30792  const double t_sub_total_create_new_adapted_mesh =
30793  TimingHelpers::timer() - t_start_create_new_adapted_mesh;
30794 
30795  // Add the time to the total snap nodes time
30796  t_total_create_new_adapted_mesh+=t_sub_total_create_new_adapted_mesh;
30797 
30798  if (Print_timings_level_adaptation>2)
30799  {
30800  // Get the number of elements of the new adapted mesh
30801  const unsigned n_element_new_adapted_mesh = new_mesh_pt->nelement();
30802 
30803  oomph_info << "CPU for creation of new adapted mesh "
30804  << t_sub_total_create_new_adapted_mesh
30805  << "[nele="<<n_element_new_adapted_mesh
30806  << "] (iter "<< iter << "): "
30807  << t_sub_total_create_new_adapted_mesh << std::endl;
30808  }
30809 
30810 #ifdef OOMPH_HAS_MPI
30811  // ------------------------------------------
30812  // DISTRIBUTED MESH: BEGIN
30813  // ------------------------------------------
30814 
30815  // This section is only required if we are dealing with
30816  // distributed meshes, otherwise there are not shared boundaries
30817  // overlapping internal boundaries
30818 
30819  // Check if necessary to fill boundary elements for those internal
30820  // boundaries that overlap shared boundaries
30821  if (this->nshared_boundary_overlaps_internal_boundary() > 0)
30822  {
30823  // Copy the data structures that indicate which shared
30824  // boundaries are part of an internal boundary
30826  this->shared_boundary_overlaps_internal_boundary();
30827 
30828  // Copy the data structure that indicates which are the shared
30829  // boundaries in each processor
30830  new_mesh_pt->shared_boundaries_ids() =
30831  this->shared_boundaries_ids();
30832 
30833  // Fill the structures for the boundary elements and face indexes
30834  // of the boundary elements
30835  new_mesh_pt->
30836  fill_boundary_elements_and_nodes_for_internal_boundaries();
30837  }
30838  // ------------------------------------------
30839  // DISTRIBUTED MESH: END
30840  // ------------------------------------------
30841 #endif // #ifdef OOMPH_HAS_MPI
30842 
30843  // Snap to curvilinear boundaries (some code duplication as this
30844  // is repeated below but helper function would take so many
30845  // arguments that it's nearly as messy...
30846 
30847  //Pass the boundary geometric objects to the new mesh
30848  new_mesh_pt->boundary_geom_object_pt() =
30849  this->boundary_geom_object_pt();
30850 
30851  // Reset the boundary coordinates if there is
30852  // a geometric object associated with the boundary
30853  new_mesh_pt->boundary_coordinate_limits() =
30854  this->boundary_coordinate_limits();
30855 
30856  const double t_start_third_stage_segments_connectivity =
30857  TimingHelpers::timer();
30858 
30859  for (unsigned b=0;b<n_boundary;b++)
30860  {
30861  // ------------------------------------------
30862  // DISTRIBUTED MESH: BEGIN
30863  // ------------------------------------------
30864 
30865  // Before setting up boundary coordinates for the new mesh we
30866  // require to identify the segments with the old mesh to
30867  // assign initial zeta values
30868 #ifdef OOMPH_HAS_MPI
30869  if (this->is_mesh_distributed())
30870  {
30871  // Identify the segments of the new mesh with the ones of
30872  // the original mesh
30873  new_mesh_pt->
30874  identify_boundary_segments_and_assign_initial_zeta_values(b,this);
30875  }
30876 #endif
30877  // ------------------------------------------
30878  // DISTRIBUTED MESH: END
30879  // ------------------------------------------
30880 
30881  // Setup boundary coordinates for boundaries with GeomObject
30882  // associated
30883  if(new_mesh_pt->boundary_geom_object_pt(b)!=0)
30884  {
30885  new_mesh_pt->template setup_boundary_coordinates<ELEMENT>(b);
30886  }
30887 
30888  }
30889 
30890  t_total_third_stage_segments_connectivity+=
30891  TimingHelpers::timer() - t_start_third_stage_segments_connectivity;
30892 
30893  const double t_start_snap_nodes_new_mesh=TimingHelpers::timer();
30894  //Move the nodes on the new boundary onto the old curvilinear
30895  //boundary. If the boundary is straight this will do precisely
30896  //nothing but will be somewhat inefficient
30897  for(unsigned b=0;b<n_boundary;b++)
30898  {
30899  this->snap_nodes_onto_boundary(new_mesh_pt,b);
30900  }
30901 
30902  const double t_sub_total_snap_nodes_new_mesh =
30903  TimingHelpers::timer() - t_start_snap_nodes_new_mesh;
30904 
30905  // Add the time to the total snap nodes time
30906  t_total_snap_nodes+=t_sub_total_snap_nodes_new_mesh;
30907 
30908  if (Print_timings_level_adaptation>2)
30909  {
30910  oomph_info << "CPU for snapping nodes onto boundaries (new mesh) "
30911  << "(iter "<<iter<<"): "
30912  << t_sub_total_snap_nodes_new_mesh<< std::endl;
30913  }
30914 
30915  // Update mesh further?
30916  if (Mesh_update_fct_pt!=0)
30917  {
30918  Mesh_update_fct_pt(new_mesh_pt);
30919  }
30920 
30921  //If we have a continuation problem
30922  //any problem in which the timestepper is a "generalisedtimestepper",
30923  //which will have been set by the problem, then ensure
30924  //all data in the new mesh has the appropriate timestepper
30925  if(dynamic_cast<GeneralisedTimeStepper*>(this->Time_stepper_pt))
30926  {
30927  new_mesh_pt->set_nodal_and_elemental_time_stepper(
30928  this->Time_stepper_pt,false);
30929  new_mesh_pt->set_mesh_level_time_stepper(this->Time_stepper_pt,false);
30930  }
30931 
30932  // Not done: get ready for another iteration
30933  iter++;
30934  delete tmp_new_mesh_pt;
30935 
30936 #ifdef OOMPH_HAS_MPI
30937  // Check whether the number of elements that need (un)refinement
30938  // from the previous iteration is the same, if that is the case
30939  // then we mark this processor as done
30940  if (n_ele_need_refinement_iter == n_ele_need_refinement)
30941  {done = true;}
30942  // Update the number of elements that require further
30943  // (un)refinement
30944  n_ele_need_refinement = n_ele_need_refinement_iter;
30945 #endif // #ifdef OOMPH_HAS_MPI
30946 
30947  // ------------------------------------------
30948  // DISTRIBUTED MESH: BEGIN
30949  // ------------------------------------------
30950 
30951  // We can only finish the iteration adaptation process if ALL
30952  // the involved processor are marked as done, otherwise, ALL
30953  // processor need to go for another iteration
30954 #ifdef OOMPH_HAS_MPI
30955  if (this->is_mesh_distributed())
30956  {
30957  // Time to check whether other processors have finish to adapt
30958  const double t_start_wait_other_processors = TimingHelpers::timer();
30959 
30960  // In case that the mesh is distributed it is necessary to
30961  // verify that no processor requires further refinement. If at
30962  // least one processor needs more refinement then all
30963  // processors need to go for another iteration to participate
30964  // in the communications
30965  unsigned this_processor_requires_another_iteration = 1;
30966 
30967  // Is this processor done?
30968  if (done){this_processor_requires_another_iteration = 0;}
30969  int nproc_not_done = this_processor_requires_another_iteration;
30970  // Get the communicator of the mesh
30971  OomphCommunicator* comm_pt = this->communicator_pt();
30972  // Communicate with all procesoors to check whether we need to
30973  // re-iterate
30974  MPI_Allreduce(&this_processor_requires_another_iteration,
30975  &nproc_not_done,1,
30976  MPI_UNSIGNED,MPI_SUM,comm_pt->mpi_comm());
30977  // Are all processors done?
30978  if (nproc_not_done > 0)
30979  {
30980  oomph_info << "At least one processors requires further refinement. "
30981  << "Go for another iteration." << std::endl;
30982  done = false;
30983  }
30984 
30985  // Total to check whether other processors have finish to
30986  // adapt
30987  const double t_sub_total_wait_other_processors =
30988  TimingHelpers::timer() - t_start_wait_other_processors;
30989 
30990  // Add to the total timings to check whether other processors
30991  // need to adapt
30992  t_total_wait_other_processors+=t_sub_total_wait_other_processors;
30993 
30994  if (Print_timings_level_adaptation>2)
30995  {
30996  oomph_info << "CPU for waiting other processors "
30997  << "(iter "<<iter<<"): "
30998  << t_sub_total_wait_other_processors
30999  << std::endl;
31000  }
31001 
31002  } // if (this->is_mesh_distributed())
31003 #endif
31004  // ------------------------------------------
31005  // DISTRIBUTED MESH: END
31006  // ------------------------------------------
31007 
31008  if (!done)
31009  {
31010  oomph_info << "Going for another iteration. Current iteration ("
31011  << iter << ")" << std::endl;
31012 
31013  // Use the new mesh as the tmp mesh
31014  tmp_new_mesh_pt=new_mesh_pt;
31015  tmp_new_triangulateio=new_mesh_pt->triangulateio_representation();
31016  }
31017 
31018  } // end of iteration (while (!done))
31019 
31020  //Delete the temporary geometric object representation of the
31021  //current mesh
31022  delete mesh_geom_obj_pt;
31023 
31024  oomph_info << "CPU for iterative generation of new mesh (TOTAL): "
31025  << TimingHelpers::timer()-t_iter
31026  << std::endl;
31027 
31028  if (Print_timings_level_adaptation>1)
31029  {
31030  oomph_info << "-- CPU for creating new adapted meshes (TOTAL): "
31031  << t_total_create_new_adapted_mesh << std::endl;
31032 
31033  oomph_info << "-- CPU for limiting target areas (TOTAL): "
31034  << t_total_limit_target_areas << std::endl;
31035 
31036  oomph_info << "-- CPU for transferring target areas (TOTAL): "
31037  << t_total_transfer_target_areas << std::endl;
31038 
31039  oomph_info << "-- CPU for waiting other processors (TOTAL): "
31040  << t_total_wait_other_processors << std::endl;
31041  }
31042 
31043  // ==============================================================
31044  // END: Transferring of target areas and creation of new mesh
31045  // ==============================================================
31046 
31047  // ==============================================================
31048  // BEGIN: Project solution from the old to the new mesh
31049  // ==============================================================
31050 
31051  // Check that the projection step is not disabled
31052  if (!Disable_projection)
31053  {
31054  // Take the time for the projection step
31055  double tt_start_projection=TimingHelpers::timer();
31056 
31057  // Print info. for tranfering target areas
31058  if (Print_timings_projection)
31059  {
31060  // Switch timings and stats on
31061  Multi_domain_functions::Doc_timings=true;
31062  Multi_domain_functions::Doc_stats=true;
31063  Multi_domain_functions::Doc_full_stats=true;
31064  }
31065 
31066  double t_proj=TimingHelpers::timer();
31067  oomph_info << "About to begin projection.\n";
31068 
31069  // Project current solution onto new mesh
31070  //---------------------------------------
31071  ProjectionProblem<ELEMENT>* project_problem_pt=
31072  new ProjectionProblem<ELEMENT>;
31073 
31074  // Projection requires to be enabled as distributed if working
31075  // with a distributed mesh
31076 #ifdef OOMPH_HAS_MPI
31077  if (this->is_mesh_distributed())
31078  {
31079  // ------------------------------------------
31080  // DISTRIBUTED MESH: BEGIN
31081  // ------------------------------------------
31082 
31083  // We need to back up the time stepper object since the
31084  // projection class creates a new one
31085  Time* backed_up_time_pt = this->Time_stepper_pt->time_pt();
31086 
31087  // Set the projection problem as distributed
31088  project_problem_pt->enable_problem_distributed();
31089 
31090  // Pass the time stepper to the projection problem (used when
31091  // setting multi_domain_interation)
31092  project_problem_pt->add_time_stepper_pt(this->Time_stepper_pt);
31093 
31094  // Set the mesh used for the projection object
31095  project_problem_pt->mesh_pt()=new_mesh_pt;
31096  //project_problem_pt->disable_suppress_output_during_projection();
31097 
31098  // Use iterative solver for projection? By default, an iterative
31099  // solver is used for the projection stage
31100  if(!this->use_iterative_solver_for_projection())
31101  {
31102  project_problem_pt->disable_use_iterative_solver_for_projection();
31103  }
31104 
31105  // Do the projection
31106  project_problem_pt->project(this);
31107 
31108  // Reset the time stepper object (only affects distributed meshes)
31109  this->Time_stepper_pt->time_pt() = backed_up_time_pt;
31110 
31111  // ------------------------------------------
31112  // DISTRIBUTED MESH: END
31113  // ------------------------------------------
31114 
31115  } // if (this->is_mesh_distributed())
31116  else
31117 #endif // #ifdef OOMPH_HAS_MPI
31118  {
31119  // Set the mesh used for the projection object
31120  project_problem_pt->mesh_pt()=new_mesh_pt;
31121 
31122  // project_problem_pt->disable_suppress_output_during_projection();
31123 
31124  // Use iterative solver for projection? By default, an iterative
31125  // solver is used for the projection stage
31126  if(!this->use_iterative_solver_for_projection())
31127  {
31128  project_problem_pt->disable_use_iterative_solver_for_projection();
31129  }
31130 
31131  // Do the projection
31132  project_problem_pt->project(this);
31133  }
31134 
31135  // Reset printing info. for projection
31136  if (Print_timings_projection)
31137  {
31138  // Switch timings and stats off
31139  Multi_domain_functions::Doc_timings=false;
31140  Multi_domain_functions::Doc_stats=false;
31141  Multi_domain_functions::Doc_full_stats=false;
31142  }
31143 
31144  // Get the total time for projection
31145  const double tt_projection = TimingHelpers::timer()-tt_start_projection;
31146 
31147  if (Print_timings_level_adaptation>1)
31148  {
31149  // Get the number of elements in the old mesh (this)
31150  const unsigned n_element = this->nelement();
31151  // Get the number of elements in the new mesh
31152  const unsigned n_element_new = new_mesh_pt->nelement();
31153  oomph_info << "CPU for projection (in mesh adaptation) "
31154  << "[n_ele_old_mesh="<< n_element
31155  <<", n_ele_new_mesh="<< n_element_new<<"]: "
31156  << tt_projection << std::endl;
31157 
31158  // ------------------------------------------
31159  // DISTRIBUTED MESH: BEGIN
31160  // ------------------------------------------
31161 #ifdef OOMPH_HAS_MPI
31162  if (this->is_mesh_distributed())
31163  {
31164  // The maximum number of elements in the mesh (over all
31165  // processors)
31166  unsigned n_this_element_new = n_element_new;
31167  unsigned n_max_element_new_global = 0;
31168  // Get the maximum number of elements over all processors
31169  MPI_Reduce(&n_this_element_new, &n_max_element_new_global,
31170  1, MPI_UNSIGNED, MPI_MAX, 0,
31171  this->communicator_pt()->mpi_comm());
31172 
31173  // The time for projection for this processor
31174  double tt_this_projection = tt_projection;
31175  double tt_global_min_projection = 0.0;
31176  double tt_global_max_projection = 0.0;
31177 
31178  // Get the minimum and maximum time for projection
31179  MPI_Reduce(&tt_this_projection, &tt_global_min_projection,
31180  1, MPI_DOUBLE, MPI_MIN, 0,
31181  this->communicator_pt()->mpi_comm());
31182  MPI_Reduce(&tt_this_projection, &tt_global_max_projection,
31183  1, MPI_DOUBLE, MPI_MAX, 0,
31184  this->communicator_pt()->mpi_comm());
31185 
31186  if (this->communicator_pt()->my_rank() == 0)
31187  {
31188  oomph_info << "CPU for projection global (MIN): "
31189  << tt_global_min_projection << std::endl;
31190  oomph_info << "CPU for projection global (MAX) "
31191  << "[n_max_ele_new_global="
31192  << n_max_element_new_global<<"]: "
31193  << tt_global_max_projection << std::endl;
31194 
31195  std::cerr << "CPU for projection global (MIN): "
31196  << tt_global_min_projection << std::endl;
31197  std::cerr << "CPU for projection global (MAX): "
31198  << "[n_max_ele_new_global="
31199  << n_max_element_new_global<<"]: "
31200  << tt_global_max_projection << std::endl;
31201 
31202  }
31203 
31204  }
31205 #endif // #ifdef OOMPH_HAS_MPI
31206  // ------------------------------------------
31207  // DISTRIBUTED MESH: END
31208  // ------------------------------------------
31209 
31210  } // if (Print_timings_level_adaptation>1)
31211 
31212  oomph_info << "CPU for projection of solution onto new mesh: "
31213  << TimingHelpers::timer()-t_proj
31214  << std::endl;
31215 
31216  // Delete the projection problem
31217  delete project_problem_pt;
31218 
31219  } // if (!Disable_projection)
31220  else
31221  {
31222  oomph_info << "Projection disabled! The new mesh will contain zeros"
31223  << std::endl;
31224  }
31225 
31226  // ==============================================================
31227  // END: Project solution from the old to the new mesh
31228  // ==============================================================
31229 
31230  double t_rest=TimingHelpers::timer();
31231 
31232  //Flush the old mesh
31233  unsigned nnod=nnode();
31234  for(unsigned j=nnod;j>0;j--)
31235  {
31236  delete Node_pt[j-1];
31237  Node_pt[j-1] = 0;
31238  }
31239  unsigned nel=nelement();
31240  for(unsigned e=nel;e>0;e--)
31241  {
31242  delete Element_pt[e-1];
31243  Element_pt[e-1] = 0;
31244  }
31245 
31246  // Now copy back to current mesh
31247  //------------------------------
31248  nnod=new_mesh_pt->nnode();
31249  Node_pt.resize(nnod);
31250  nel=new_mesh_pt->nelement();
31251  Element_pt.resize(nel);
31252  for(unsigned j=0;j<nnod;j++)
31253  {
31254  Node_pt[j] = new_mesh_pt->node_pt(j);
31255  }
31256  for(unsigned e=0;e<nel;e++)
31257  {
31258  Element_pt[e] = new_mesh_pt->element_pt(e);
31259  }
31260 
31261  // Copy the boundary elements information from the new mesh to the
31262  // original mesh
31263  unsigned nbound = 0;
31264 
31265 #ifdef OOMPH_HAS_MPI
31266  // If working with a distributed mesh we need to change the number
31267  // of boundaries so that shared boundaries information is also
31268  // copied from the old to the new mesh
31269  if (this->is_mesh_distributed())
31270  {
31271  // The boundaries to be copied include those new ones in the new
31272  // mesh (shared boundaries). This info. is required to
31273  // re-establish the halo/haloed scheme
31274  nbound = new_mesh_pt->nboundary();
31275  // After halo and haloed scheme has been re-established the
31276  // number of boundaries is changed to the original number of
31277  // boundaries
31278  }
31279  else
31280 #endif
31281  {
31282  // The original number of boundaries
31283  nbound = n_boundary;
31284  }
31285 
31286  Boundary_element_pt.resize(nbound);
31287  Face_index_at_boundary.resize(nbound);
31288  Boundary_node_pt.resize(nbound);
31289  for (unsigned b=0;b<nbound;b++)
31290  {
31291  unsigned nel=new_mesh_pt->nboundary_element(b);
31292  Boundary_element_pt[b].resize(nel);
31293  Face_index_at_boundary[b].resize(nel);
31294  for (unsigned e=0;e<nel;e++)
31295  {
31296  Boundary_element_pt[b][e]=new_mesh_pt->boundary_element_pt(b,e);
31297  Face_index_at_boundary[b][e]=new_mesh_pt->face_index_at_boundary(b,e);
31298  }
31299  unsigned nnod=new_mesh_pt->nboundary_node(b);
31300  Boundary_node_pt[b].resize(nnod);
31301  for (unsigned j=0;j<nnod;j++)
31302  {
31303  Boundary_node_pt[b][j]=new_mesh_pt->boundary_node_pt(b,j);
31304  }
31305  }
31306 
31307  //Also copy over the new boundary and region information
31308  unsigned n_region = new_mesh_pt->nregion();
31309  // Only bother if we have regions
31310  if(n_region > 1)
31311  {
31312  //Deal with the region information first
31313  this->Region_attribute.resize(n_region);
31314  for(unsigned r=0;r<n_region;r++)
31315  {
31316  this->Region_attribute[r] = new_mesh_pt->region_attribute(r);
31317  // Get the region id
31318  unsigned r_id = static_cast<unsigned>(this->Region_attribute[r]);
31319  //Find the number of elements in the region
31320  unsigned n_region_element = new_mesh_pt->nregion_element(r_id);
31321  this->Region_element_pt[r_id].resize(n_region_element);
31322  for(unsigned e=0;e<n_region_element;e++)
31323  {
31324  this->Region_element_pt[r_id][e] =
31325  new_mesh_pt->region_element_pt(r_id,e);
31326  }
31327  }
31328 
31329  //Now the boundary region information
31330  this->Boundary_region_element_pt.resize(nbound);
31331  this->Face_index_region_at_boundary.resize(nbound);
31332 
31333  //Now loop over the boundaries
31334  for(unsigned b=0;b<nbound;++b)
31335  {
31336  for (unsigned rr = 0 ; rr < n_region; rr++)
31337  {
31338  // The region id
31339  unsigned r = static_cast<unsigned>(this->Region_attribute[rr]);
31340 
31341  unsigned n_boundary_el_in_region =
31342  new_mesh_pt->nboundary_element_in_region(b,r);
31343 
31344  if(n_boundary_el_in_region > 0)
31345  {
31346  //Allocate storage in the map
31347  this->Boundary_region_element_pt[b][r].
31348  resize(n_boundary_el_in_region);
31349  this->Face_index_region_at_boundary[b][r].
31350  resize(n_boundary_el_in_region);
31351 
31352  //Copy over the information
31353  for(unsigned e=0;e<n_boundary_el_in_region;++e)
31354  {
31355  this->Boundary_region_element_pt[b][r][e]
31356  = new_mesh_pt->boundary_element_in_region_pt(b,r,e);
31357  this->Face_index_region_at_boundary[b][r][e]
31358  = new_mesh_pt->face_index_at_boundary_in_region(b,r,e);
31359  }
31360  }
31361  }
31362  } //End of loop over boundaries
31363 
31364  } //End of case when more than one region
31365 
31366  // ------------------------------------------
31367  // DISTRIBUTED MESH: BEGIN
31368  // ------------------------------------------
31369 
31370  // Re-generate halo(ed) information (only for distributed meshes)
31371 #ifdef OOMPH_HAS_MPI
31372  if (this->is_mesh_distributed())
31373  {
31374  // Delete halo(ed) information in the original mesh, the new
31375  // halo(ed) information is generated usign the info. of the new
31376  // mesh
31377  if (this->is_mesh_distributed())
31378  {
31379  this->Halo_node_pt.clear();
31380  this->Root_halo_element_pt.clear();
31381 
31382  this->Haloed_node_pt.clear();
31383  this->Root_haloed_element_pt.clear();
31384 
31385  this->External_halo_node_pt.clear();
31386  this->External_halo_element_pt.clear();
31387 
31388  this->External_haloed_node_pt.clear();
31389  this->External_haloed_element_pt.clear();
31390  }
31391 
31392  // Re-establish the shared boundary elements and nodes scheme
31393  // before re-establish halo(ed) information
31394  this->reset_shared_boundary_elements_and_nodes();
31395 
31396  // -------------------------------------------------------------
31397  // Remove shared boundary elements and nodes from original
31398  // boundary elements and boundary nodes containers. Shared
31399  // boundary elements and nodes are stored in a special
31400  // container.
31401 
31402  // Get the shared boundaries in this processor with any other
31403  // processor
31404  Vector<unsigned> my_rank_shared_boundaries_ids;
31405  this->shared_boundaries_in_this_processor(my_rank_shared_boundaries_ids);
31406 
31407  // Get the number of shared boundaries
31408  const unsigned nmy_rank_shd_bnd = my_rank_shared_boundaries_ids.size();
31409  // Loop over the shared boundaries marked as original boundaries
31410  // in tmp_new_mesh
31411  for (unsigned i = 0; i < nmy_rank_shd_bnd; i++)
31412  {
31413  // Get the boundary id
31414  const unsigned shd_bnd_id = my_rank_shared_boundaries_ids[i];
31415  // Flush any previous relation of shared boundary elements
31416  // marked as original boundary elements in tmp_new_mesh
31417  this->Boundary_element_pt[shd_bnd_id].clear();
31418 
31419  // Get the number of nodes associated with the original
31420  // boundary in tmp_new_mesh that is a shared boundary
31421  const unsigned tmp_nnodes =
31422  this->nshared_boundary_node(shd_bnd_id);
31423  for (unsigned n = 0; n < tmp_nnodes; n++)
31424  {
31425  Node* tmp_node_pt = this->boundary_node_pt(shd_bnd_id, n);
31426  tmp_node_pt->remove_from_boundary(shd_bnd_id);
31427  } // for (n < nnodes)
31428 
31429  } // for (shd_bnd_id < nmy_rank_shd_bnd)
31430 
31431  // Re-set the number of boundaries to the original one
31432  this->set_nboundary(n_boundary);
31433 
31434  // Sort the nodes on the boundaries so that they have the same
31435  // order on all the boundaries
31436  this->sort_nodes_on_shared_boundaries();
31437 
31438  // Re-set the halo(ed) scheme
31439  this->reset_halo_haloed_scheme();
31440 
31441  // Set the correct number of segments for the boundaries with
31442  // geom objects associated
31443  for (unsigned b = 0; b < n_boundary; b++)
31444  {
31445  if (this->boundary_geom_object_pt(b)!=0)
31446  {
31447  const unsigned nsegments = new_mesh_pt->nboundary_segment(b);
31448  this->set_nboundary_segment_node(b, nsegments);
31449  }
31450  }
31451 
31452  // Resume the connections in boundaries were it was suspended
31453  resume_boundary_connections(resume_initial_connection_polyline_pt,
31454  resume_final_connection_polyline_pt);
31455 
31456  } // if (this->is_mesh_distributed())
31457 
31458 #endif // #ifdef OOMPH_HAS_MPI
31459 
31460  // ------------------------------------------
31461  // DISTRIBUTED MESH: END
31462  // ------------------------------------------
31463 
31464  //Snap the newly created nodes onto any geometric objects
31465  this->snap_nodes_onto_geometric_objects();
31466 
31467  // Copy the IDs of the vertex nodes
31468  this->Oomph_vertex_nodes_id=new_mesh_pt->oomph_vertex_nodes_id();
31469 
31470  // Copy TriangulateIO representation
31471  TriangleHelper::clear_triangulateio(this->Triangulateio);
31472  bool quiet=true;
31473  this->Triangulateio=
31474  TriangleHelper::deep_copy_of_triangulateio_representation(
31475  new_mesh_pt->triangulateio_representation(),quiet);
31476 
31477  // Flush the mesh
31478  new_mesh_pt->flush_element_and_node_storage();
31479 
31480  // Delete the mesh
31481  delete new_mesh_pt;
31482 
31483  // Resume of timings
31484  if (Print_timings_level_adaptation>2)
31485  {
31486  // Report timings related with setting boundary coordinates of
31487  // nodes on segments
31488  oomph_info << "CPU for segments connectivity (first stage) [sec]: "
31489  << t_total_first_stage_segments_connectivity << std::endl;
31490  oomph_info << "CPU for segments connectivity (second stage) [sec]: "
31491  << t_total_second_stage_segments_connectivity << std::endl;
31492  oomph_info << "CPU for segments connectivity (third stage) [sec]: "
31493  << t_total_third_stage_segments_connectivity << std::endl;
31494  }
31495 
31496  if (Print_timings_level_adaptation>1)
31497  {
31498  const double t_total_segments_connectivity =
31499  t_total_first_stage_segments_connectivity +
31500  t_total_second_stage_segments_connectivity +
31501  t_total_third_stage_segments_connectivity;
31502 
31503  oomph_info << "CPU for segments connectivity (TOTAL) [sec]: "
31504  << t_total_segments_connectivity << std::endl;
31505 
31506  if (Print_timings_level_adaptation>2)
31507  {
31508  // Report timings for snapping of nodes onto boundaries
31509  oomph_info << "CPU for snapping nodes onto boundaries "
31510  << "(new mesh): "
31511  << t_total_snap_nodes << std::endl;
31512  }
31513 
31514  t_total_snap_nodes+=t_total_snap_nodes_bg_mesh;
31515  oomph_info << "CPU for snapping nodes onto boundaries (TOTAL): "
31516  << t_total_snap_nodes << std::endl;
31517  }
31518 
31519  double max_area=0.0;
31520  double min_area=0.0;
31521 
31522  this->max_and_min_element_size(max_area, min_area);
31523  oomph_info << "Max/min element size in adapted mesh: "
31524  << max_area << " "
31525  << min_area << std::endl;
31526 
31527  oomph_info << "CPU time for final bits [sec]: "
31528  << TimingHelpers::timer()-t_rest
31529  << std::endl;
31530  }
31531  else
31532  {
31533  oomph_info << "Not enough benefit in adaptation.\n";
31534  Nrefined=0;
31535  Nunrefined=0;
31536  }
31537 
31538  double CPU_for_adaptation = TimingHelpers::timer()-t_start_overall;
31539  oomph_info <<"CPU time for adaptation [sec]: "
31540  << CPU_for_adaptation << std::endl;
31541 
31542  // ------------------------------------------
31543  // DISTRIBUTED MESH: BEGIN
31544  // ------------------------------------------
31545 #ifdef OOMPH_HAS_MPI
31546  if (this->is_mesh_distributed())
31547  {
31548  // Get the communicator
31549  OomphCommunicator* comm_pt = this->communicator_pt();
31550  // Get the total number of processors to compute the average
31551  const unsigned n_proc = comm_pt->nproc();
31552  if (Print_timings_level_adaptation>1 && n_proc>1)
31553  {
31554  double global_min_CPU_for_adaptation = 0.0;
31555  double global_max_CPU_for_adaptation = 0.0;
31556  double global_average_CPU_for_adaptation = 0.0;
31557 
31558  // Get the maximum and minimum of the adaptation times
31559  MPI_Reduce(&CPU_for_adaptation, &global_min_CPU_for_adaptation,
31560  1, MPI_DOUBLE, MPI_MIN, 0, comm_pt->mpi_comm());
31561  MPI_Reduce(&CPU_for_adaptation, &global_max_CPU_for_adaptation,
31562  1, MPI_DOUBLE, MPI_MAX, 0, comm_pt->mpi_comm());
31563  MPI_Reduce(&CPU_for_adaptation, &global_average_CPU_for_adaptation,
31564  1, MPI_DOUBLE, MPI_SUM, 0, comm_pt->mpi_comm());
31565 
31566  // Get the rank of the processor
31567  const unsigned my_rank = comm_pt->my_rank();
31568  if (my_rank==0)
31569  {
31570  oomph_info << "CPU for adaptation (MIN): "
31571  << global_min_CPU_for_adaptation << std::endl;
31572  oomph_info << "CPU for adaptation (MAX): "
31573  << global_max_CPU_for_adaptation << std::endl;
31574  oomph_info << "CPU for adaptation (AVERAGE): "
31575  << global_average_CPU_for_adaptation/n_proc << std::endl;
31576  } // if (my_rank==0)
31577 
31578  } // if (Print_timings_level_adaptation>1&&n_proc>1)
31579 
31580  } // if (this->is_mesh_distributed())
31581 
31582  // ------------------------------------------
31583  // DISTRIBUTED MESH: END
31584  // ------------------------------------------
31585 
31586 #endif // #ifdef OOMPH_HAS_MPI
31587 
31588 
31589 
31590  }
31591 
31592 //=========================================================================
31593  /// \ short Mark the vertices that are not allowed for deletion by
31594  /// the unrefienment/refinement polyline methods. In charge of
31595  /// filling the Boundary_connections_pt structure
31596  //=========================================================================
31597  template<class ELEMENT>
31599  {
31600  // Clear any previous information
31601  //Boundary_chunk_connections_pt.clear();
31602  Boundary_connections_pt.clear();
31603 
31604  // Loop over the boundaries in the domain (outer, internal -- closed
31605  // and open ---, and shared) and get the boundaries ids with
31606  // connections (have or receive)
31607 
31608  // Store the boundaries ids that have or receive connection
31609  std::set<unsigned> boundary_id_with_connections;
31610 
31611  // ------------------------------------------------------------------
31612  // Outer boundaries
31613  // ------------------------------------------------------------------
31614 
31615  // Get the number of outer boundaries (closed boundaries)
31616  const unsigned n_outer_boundaries = this->Outer_boundary_pt.size();
31617 
31618  // Loop over the outer boundaries
31619  for (unsigned i = 0; i < n_outer_boundaries; i++)
31620  {
31621  // Get a temporary polygon representation
31622  TriangleMeshPolygon* tmp_polygon_pt = this->Outer_boundary_pt[i];
31623  // Get the number of polylines associated to the current outer
31624  // boundary
31625  const unsigned n_polyline = tmp_polygon_pt->npolyline();
31626  // Loop over the polylines
31627  for (unsigned p = 0; p < n_polyline; p++)
31628  {
31629  // Get a temporary representation of the polyline
31630  TriangleMeshPolyLine* tmp_polyline_pt =
31631  tmp_polygon_pt->polyline_pt(p);
31632 
31633  // Is the initial vertex connected?
31634  if (tmp_polyline_pt->is_initial_vertex_connected())
31635  {
31636  // Get the boundary id of the current polyline
31637  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31638 
31639  // Include the boundary id to the set of boundaries with
31640  // connections
31641  boundary_id_with_connections.insert(bnd_id);
31642 
31643  // Boundary id to which the curve is connecte
31644  const unsigned dst_bnd_id =
31645  tmp_polyline_pt->initial_vertex_connected_bnd_id();
31646 
31647  // Include the destination boundary id to the set of
31648  // boundaries with connections
31649  boundary_id_with_connections.insert(dst_bnd_id);
31650 
31651  } // if (tmp_polyline_pt->is_initial_vertex_connected())
31652 
31653  // Is the final vertex connected?
31654  if (tmp_polyline_pt->is_final_vertex_connected())
31655  {
31656  // Get the boundary id of the current polyline
31657  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31658 
31659  // Include the boundary id to the set of boundaries with
31660  // connections
31661  boundary_id_with_connections.insert(bnd_id);
31662 
31663  // Boundary id to which the curve is connected
31664  const unsigned dst_bnd_id =
31665  tmp_polyline_pt->final_vertex_connected_bnd_id();
31666 
31667  // Include the destination boundary id to the set of
31668  // boundaries with connections
31669  boundary_id_with_connections.insert(dst_bnd_id);
31670 
31671  } // if (tmp_polyline_pt->is_final_vertex_connected())
31672 
31673  } // for (p < n_polyline)
31674 
31675  } // for (i < n_outer_boundaries)
31676 
31677  // ------------------------------------------------------------------
31678  // Internal boundaries
31679  // ------------------------------------------------------------------
31680 
31681  // Get the number of internal boundaries (closed boundaries)
31682  const unsigned n_internal_boundaries = this->Internal_polygon_pt.size();
31683 
31684  // Loop over the internal boundaries
31685  for (unsigned i = 0; i < n_internal_boundaries; i++)
31686  {
31687  // Get a temporary polygon representation
31688  TriangleMeshPolygon* tmp_polygon_pt = this->Internal_polygon_pt[i];
31689  // Get the number of polylines associated to the current internal
31690  // boundary
31691  const unsigned n_polyline = tmp_polygon_pt->npolyline();
31692  // Loop over the polylines
31693  for (unsigned p = 0; p < n_polyline; p++)
31694  {
31695  // Get a temporary representation of the polyline
31696  TriangleMeshPolyLine* tmp_polyline_pt =
31697  tmp_polygon_pt->polyline_pt(p);
31698 
31699  // Is the initial vertex connected?
31700  if (tmp_polyline_pt->is_initial_vertex_connected())
31701  {
31702  // Get the boundary id of the current polyline
31703  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31704 
31705  // Include the boundary id to the set of boundaries with
31706  // connections
31707  boundary_id_with_connections.insert(bnd_id);
31708 
31709  // Boundary id to which the curve is connecte
31710  const unsigned dst_bnd_id =
31711  tmp_polyline_pt->initial_vertex_connected_bnd_id();
31712 
31713  // Include the destination boundary id to the set of
31714  // boundaries with connections
31715  boundary_id_with_connections.insert(dst_bnd_id);
31716 
31717  } // if (tmp_polyline_pt->is_initial_vertex_connected())
31718 
31719  // Is the final vertex connected?
31720  if (tmp_polyline_pt->is_final_vertex_connected())
31721  {
31722  // Get the boundary id of the current polyline
31723  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31724 
31725  // Include the boundary id to the set of boundaries with
31726  // connections
31727  boundary_id_with_connections.insert(bnd_id);
31728 
31729  // Boundary id to which the curve is connected
31730  const unsigned dst_bnd_id =
31731  tmp_polyline_pt->final_vertex_connected_bnd_id();
31732 
31733  // Include the destination boundary id to the set of
31734  // boundaries with connections
31735  boundary_id_with_connections.insert(dst_bnd_id);
31736 
31737  } // if (tmp_polyline_pt->is_final_vertex_connected())
31738 
31739  } // for (p < n_polyline)
31740 
31741  } // for (i < n_internal_boundaries)
31742 
31743  // ------------------------------------------------------------------
31744  // Open boundaries (nonclosed internal boundaries)
31745  // ------------------------------------------------------------------
31746 
31747  // Get the number of internal boundaries (open boundaries)
31748  const unsigned n_open_boundaries = this->Internal_open_curve_pt.size();
31749 
31750  // Loop over the internal open boundaries
31751  for (unsigned i = 0; i < n_open_boundaries; i++)
31752  {
31753  // Get a temporary representation for the open curve
31754  TriangleMeshOpenCurve* tmp_open_curve_pt =
31755  this->Internal_open_curve_pt[i];
31756 
31757  // Get the number of curve sections associated to the current
31758  // internal open boundary
31759  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
31760 
31761  // Loop over the curve section
31762  for (unsigned p = 0; p < n_curve_section; p++)
31763  {
31764  // Get a temporary representation of the curve section
31765  // (polyline)
31766  TriangleMeshPolyLine* tmp_polyline_pt =
31767  tmp_open_curve_pt->polyline_pt(p);
31768 
31769  // Is the initial vertex connected?
31770  if (tmp_polyline_pt->is_initial_vertex_connected())
31771  {
31772  // Get the boundary id of the current polyline
31773  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31774 
31775  // Include the boundary id to the set of boundaries with
31776  // connections
31777  boundary_id_with_connections.insert(bnd_id);
31778 
31779  // Boundary id to which the curve is connecte
31780  const unsigned dst_bnd_id =
31781  tmp_polyline_pt->initial_vertex_connected_bnd_id();
31782 
31783  // Include the destination boundary id to the set of
31784  // boundaries with connections
31785  boundary_id_with_connections.insert(dst_bnd_id);
31786 
31787  } // if (tmp_polyline_pt->is_initial_vertex_connected())
31788 
31789  // Is the final vertex connected?
31790  if (tmp_polyline_pt->is_final_vertex_connected())
31791  {
31792  // Get the boundary id of the current polyline
31793  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31794 
31795  // Include the boundary id to the set of boundaries with
31796  // connections
31797  boundary_id_with_connections.insert(bnd_id);
31798 
31799  // Boundary id to which the curve is connected
31800  const unsigned dst_bnd_id =
31801  tmp_polyline_pt->final_vertex_connected_bnd_id();
31802 
31803  // Include the destination boundary id to the set of
31804  // boundaries with connections
31805  boundary_id_with_connections.insert(dst_bnd_id);
31806 
31807  } // if (tmp_polyline_pt->is_final_vertex_connected())
31808 
31809  } // for (p < n_curve_section)
31810 
31811  } // for (i < n_open_boundaries)
31812 
31813 #ifdef OOMPH_HAS_MPI
31814  // ------------------------------------------------------------------
31815  // Shared boundaries (only for distributed meshes)
31816  // ------------------------------------------------------------------
31817 
31818  // Check if we need to include any information associated with
31819  // shared boundaries
31820  if (this->is_mesh_distributed())
31821  {
31822  // Get the rank of the current processor
31823  const unsigned my_rank = this->communicator_pt()->my_rank();
31824 
31825  // Get the number of shared curves in the current processor
31826  const unsigned n_shared_curves =
31827  this->nshared_boundary_curves(my_rank);
31828 
31829  // Loop over the shared curves
31830  for (unsigned i = 0; i < n_shared_curves; i ++)
31831  {
31832  // Get the number of polylines associated to the current shared
31833  // curve
31834  const unsigned n_polyline =
31835  this->nshared_boundary_polyline(my_rank, i);
31836 
31837  // Loop over the polylines associated to the current shared
31838  // curve
31839  for (unsigned p = 0; p < n_polyline; p++)
31840  {
31841  // Get a temporary representation of the shared polyline
31842  TriangleMeshPolyLine* tmp_polyline_pt =
31843  this->shared_boundary_polyline_pt(my_rank, i, p);
31844 
31845  // Is the initial vertex connected?
31846  if (tmp_polyline_pt->is_initial_vertex_connected())
31847  {
31848  // Get the boundary id of the current polyline
31849  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31850 
31851  // Include the boundary id to the set of boundaries with
31852  // connections
31853  boundary_id_with_connections.insert(bnd_id);
31854 
31855  // Boundary id to which the curve is connecte
31856  const unsigned dst_bnd_id =
31857  tmp_polyline_pt->initial_vertex_connected_bnd_id();
31858 
31859  // Include the destination boundary id to the set of
31860  // boundaries with connections
31861  boundary_id_with_connections.insert(dst_bnd_id);
31862 
31863  } // if (tmp_polyline_pt->is_initial_vertex_connected())
31864 
31865  // Is the final vertex connected?
31866  if (tmp_polyline_pt->is_final_vertex_connected())
31867  {
31868  // Get the boundary id of the current polyline
31869  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31870 
31871  // Include the boundary id to the set of boundaries with
31872  // connections
31873  boundary_id_with_connections.insert(bnd_id);
31874 
31875  // Boundary id to which the curve is connected
31876  const unsigned dst_bnd_id =
31877  tmp_polyline_pt->final_vertex_connected_bnd_id();
31878 
31879  // Include the destination boundary id to the set of
31880  // boundaries with connections
31881  boundary_id_with_connections.insert(dst_bnd_id);
31882 
31883  } // if (tmp_polyline_pt->is_final_vertex_connected())
31884 
31885  } // for (p < n_polyline)
31886 
31887  } // for (i < n_shared_curves)
31888 
31889  } // if (this->is_mesh_distributed())
31890 
31891 #endif // #ifdef OOMPH_HAS_MPI
31892 
31893  // ---------------------------------------------------------------
31894  // Get the nodes sorted by segments of the boundaries with
31895  // connections
31896 
31897  // Store the sorted nodes by segments of the boundaries with
31898  // connections
31899  std::map<unsigned, Vector<Vector<Node*> > > bnd_sorted_segment_node_pt;
31900 
31901  // Loop over the boundaries with connections
31902  for (std::set<unsigned>::iterator it =
31903  boundary_id_with_connections.begin();
31904  it != boundary_id_with_connections.end(); it++)
31905  {
31906  // Get the boundary id
31907  const unsigned bnd_id = (*it);
31908 #ifdef OOMPH_HAS_MPI
31909  // Working with a distributed mesh
31910  if (this->is_mesh_distributed())
31911  {
31912  // Get the initial shared boundary id
31913  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
31914  // Is an original or shared boundary
31915  if (bnd_id >= init_shd_bnd_id)
31916  {
31917  // Is a shared boundary
31918 
31919  // Temporary storage for the nodes on the shared boundary
31920  Vector<Vector<Node*> > tmp_shared_nodes_pt;
31921 
31922  // Get the nodes associated to the shared boundary
31923  get_shared_boundary_segment_nodes_helper(bnd_id,
31924  tmp_shared_nodes_pt);
31925 
31926  // Store the nodes associated to the shared boundary
31927  bnd_sorted_segment_node_pt[bnd_id] = tmp_shared_nodes_pt;
31928 
31929  } // if (bnd_id >= init_shd_bnd_id)
31930  else
31931  {
31932  // Is an original boundary
31933 
31934  // Temporary storage for the nodes on the original boundary
31935  Vector<Vector<Node*> > tmp_boundary_nodes_pt;
31936 
31937  // Get the nodes associated to the shared boundary
31938  get_boundary_segment_nodes_helper(bnd_id,
31939  tmp_boundary_nodes_pt);
31940 
31941  // Store the nodes associated to the shared boundary
31942  bnd_sorted_segment_node_pt[bnd_id] = tmp_boundary_nodes_pt;
31943 
31944  } // if (bnd_id >= init_shd_bnd_id)
31945 
31946  } // if (this->is_mesh_distributed())
31947  else
31948 #endif // #ifdef OOMPH_HAS_MPI
31949  {
31950  // Is an original boundary
31951 
31952  // Temporary storage for the nodes on the original boundary
31953  Vector<Vector<Node*> > tmp_boundary_nodes_pt;
31954 
31955  // Get the nodes associated to the shared boundary
31956  get_boundary_segment_nodes_helper(bnd_id,
31957  tmp_boundary_nodes_pt);
31958 
31959  // Store the nodes associated to the shared boundary
31960  bnd_sorted_segment_node_pt[bnd_id] = tmp_boundary_nodes_pt;
31961 
31962  } // if (this->is_mesh_distributed())
31963 
31964  } // Loop over boundaries with connections
31965 
31966  // -----------------------------------------------------------------
31967  // Loop again over the boundaries (original and shared) and search
31968  // for the repeated nodes in those boundaries with connections
31969 
31970  // ------------------------------------------------------------------
31971  // Outer boundaries
31972  // ------------------------------------------------------------------
31973  // Loop over the outer boundaries
31974  for (unsigned i = 0; i < n_outer_boundaries; i++)
31975  {
31976  // Get a temporary polygon representation
31977  TriangleMeshPolygon* tmp_polygon_pt = this->Outer_boundary_pt[i];
31978  // Get the number of polylines associated to the current outer
31979  // boundary
31980  const unsigned n_polyline = tmp_polygon_pt->npolyline();
31981  // Loop over the polylines
31982  for (unsigned p = 0; p < n_polyline; p++)
31983  {
31984  // Get a temporary representation of the polyline
31985  TriangleMeshPolyLine* tmp_polyline_pt =
31986  tmp_polygon_pt->polyline_pt(p);
31987 
31988  // Is the initial vertex connected?
31989  if (tmp_polyline_pt->is_initial_vertex_connected())
31990  {
31991  // Get the boundary id of the current polyline
31992  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
31993 
31994  // Boundary id to which the curve is connected
31995  const unsigned dst_bnd_id =
31996  tmp_polyline_pt->initial_vertex_connected_bnd_id();
31997 
31998  // Boundary chunk to which the curve is connected
31999  const unsigned dst_chunk =
32000  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32001 
32002  // Get the nodes representation of the current boundary
32003  Vector<Vector<Node*> > src_bnd_node_pt =
32004  bnd_sorted_segment_node_pt[bnd_id];
32005 
32006  // Get the nodes representation of the boundary to connect
32007  Vector<Vector<Node*> > dst_bnd_node_pt =
32008  bnd_sorted_segment_node_pt[dst_bnd_id];
32009 
32010  // Add the repeated node to the list of non delete-able
32011  // vertices
32012  add_non_delete_vertices_from_boundary_helper(
32013  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32014 
32015  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32016 
32017  // Is the final vertex connected?
32018  if (tmp_polyline_pt->is_final_vertex_connected())
32019  {
32020  // Get the boundary id of the current polyline
32021  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32022 
32023  // Boundary id to which the curve is connected
32024  const unsigned dst_bnd_id =
32025  tmp_polyline_pt->final_vertex_connected_bnd_id();
32026 
32027  // Boundary chunk to which the curve is connected
32028  const unsigned dst_chunk =
32029  tmp_polyline_pt->final_vertex_connected_n_chunk();
32030 
32031  // Get the nodes representation of the current boundary
32032  Vector<Vector<Node*> > src_bnd_node_pt =
32033  bnd_sorted_segment_node_pt[bnd_id];
32034 
32035  // Get the nodes representation of the boundary to connect
32036  Vector<Vector<Node*> > dst_bnd_node_pt =
32037  bnd_sorted_segment_node_pt[dst_bnd_id];
32038 
32039  // Add the repeated node to the list of non delete-able
32040  // vertices
32041  add_non_delete_vertices_from_boundary_helper(
32042  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32043 
32044  } // if (tmp_polyline_pt->is_final_vertex_connected())
32045 
32046  } // for (p < n_polyline)
32047 
32048  } // for (i < n_outer_boundaries)
32049 
32050  // ------------------------------------------------------------------
32051  // Internal boundaries
32052  // ------------------------------------------------------------------
32053  // Loop over the internal boundaries
32054  for (unsigned i = 0; i < n_internal_boundaries; i++)
32055  {
32056  // Get a temporary polygon representation
32057  TriangleMeshPolygon* tmp_polygon_pt = this->Internal_polygon_pt[i];
32058  // Get the number of polylines associated to the current internal
32059  // boundary
32060  const unsigned n_polyline = tmp_polygon_pt->npolyline();
32061  // Loop over the polylines
32062  for (unsigned p = 0; p < n_polyline; p++)
32063  {
32064  // Get a temporary representation of the polyline
32065  TriangleMeshPolyLine* tmp_polyline_pt =
32066  tmp_polygon_pt->polyline_pt(p);
32067 
32068  // Is the initial vertex connected?
32069  if (tmp_polyline_pt->is_initial_vertex_connected())
32070  {
32071  // Get the boundary id of the current polyline
32072  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32073 
32074  // Boundary id to which the curve is connected
32075  const unsigned dst_bnd_id =
32076  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32077 
32078  // Boundary chunk to which the curve is connected
32079  const unsigned dst_chunk =
32080  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32081 
32082  // Get the nodes representation of the current boundary
32083  Vector<Vector<Node*> > src_bnd_node_pt =
32084  bnd_sorted_segment_node_pt[bnd_id];
32085 
32086  // Get the nodes representation of the boundary to connect
32087  Vector<Vector<Node*> > dst_bnd_node_pt =
32088  bnd_sorted_segment_node_pt[dst_bnd_id];
32089 
32090  // Add the repeated node to the list of non delete-able
32091  // vertices
32092  add_non_delete_vertices_from_boundary_helper(
32093  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32094 
32095  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32096 
32097  // Is the final vertex connected?
32098  if (tmp_polyline_pt->is_final_vertex_connected())
32099  {
32100  // Get the boundary id of the current polyline
32101  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32102 
32103  // Boundary id to which the curve is connected
32104  const unsigned dst_bnd_id =
32105  tmp_polyline_pt->final_vertex_connected_bnd_id();
32106 
32107  // Boundary chunk to which the curve is connected
32108  const unsigned dst_chunk =
32109  tmp_polyline_pt->final_vertex_connected_n_chunk();
32110 
32111  // Get the nodes representation of the current boundary
32112  Vector<Vector<Node*> > src_bnd_node_pt =
32113  bnd_sorted_segment_node_pt[bnd_id];
32114 
32115  // Get the nodes representation of the boundary to connect
32116  Vector<Vector<Node*> > dst_bnd_node_pt =
32117  bnd_sorted_segment_node_pt[dst_bnd_id];
32118 
32119  // Add the repeated node to the list of non delete-able
32120  // vertices
32121  add_non_delete_vertices_from_boundary_helper(
32122  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32123 
32124  } // if (tmp_polyline_pt->is_final_vertex_connected())
32125 
32126  } // for (p < n_polyline)
32127 
32128  } // for (i < n_internal_boundaries)
32129 
32130  // ------------------------------------------------------------------
32131  // Open boundaries (nonclosed internal boundaries)
32132  // ------------------------------------------------------------------
32133  // Loop over the internal open boundaries
32134  for (unsigned i = 0; i < n_open_boundaries; i++)
32135  {
32136  // Get a temporary representation for the open curve
32137  TriangleMeshOpenCurve* tmp_open_curve_pt =
32138  this->Internal_open_curve_pt[i];
32139 
32140  // Get the number of curve sections associated to the current
32141  // internal open boundary
32142  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
32143 
32144  // Loop over the curve section
32145  for (unsigned p = 0; p < n_curve_section; p++)
32146  {
32147  // Get a temporary representation of the curve section
32148  // (polyline)
32149  TriangleMeshPolyLine* tmp_polyline_pt =
32150  tmp_open_curve_pt->polyline_pt(p);
32151 
32152  // Is the initial vertex connected?
32153  if (tmp_polyline_pt->is_initial_vertex_connected())
32154  {
32155  // Get the boundary id of the current polyline
32156  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32157 
32158  // Boundary id to which the curve is connected
32159  const unsigned dst_bnd_id =
32160  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32161 
32162  // Boundary chunk to which the curve is connected
32163  const unsigned dst_chunk =
32164  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32165 
32166  // Get the nodes representation of the current boundary
32167  Vector<Vector<Node*> > src_bnd_node_pt =
32168  bnd_sorted_segment_node_pt[bnd_id];
32169 
32170  // Get the nodes representation of the boundary to connect
32171  Vector<Vector<Node*> > dst_bnd_node_pt =
32172  bnd_sorted_segment_node_pt[dst_bnd_id];
32173 
32174  // Add the repeated node to the list of non delete-able
32175  // vertices
32176  add_non_delete_vertices_from_boundary_helper(
32177  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32178 
32179  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32180 
32181  // Is the final vertex connected?
32182  if (tmp_polyline_pt->is_final_vertex_connected())
32183  {
32184  // Get the boundary id of the current polyline
32185  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32186 
32187  // Boundary id to which the curve is connected
32188  const unsigned dst_bnd_id =
32189  tmp_polyline_pt->final_vertex_connected_bnd_id();
32190 
32191  // Boundary chunk to which the curve is connected
32192  const unsigned dst_chunk =
32193  tmp_polyline_pt->final_vertex_connected_n_chunk();
32194 
32195  // Get the nodes representation of the current boundary
32196  Vector<Vector<Node*> > src_bnd_node_pt =
32197  bnd_sorted_segment_node_pt[bnd_id];
32198 
32199  // Get the nodes representation of the boundary to connect
32200  Vector<Vector<Node*> > dst_bnd_node_pt =
32201  bnd_sorted_segment_node_pt[dst_bnd_id];
32202 
32203  // Add the repeated node to the list of non delete-able
32204  // vertices
32205  add_non_delete_vertices_from_boundary_helper(
32206  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32207 
32208  } // if (tmp_polyline_pt->is_final_vertex_connected())
32209 
32210  } // for (p < n_curve_section)
32211 
32212  } // for (i < n_open_boundaries)
32213 
32214 #ifdef OOMPH_HAS_MPI
32215  // ------------------------------------------------------------------
32216  // Shared boundaries (only for distributed meshes)
32217  // ------------------------------------------------------------------
32218 
32219  // Check if we need to include any information associated with
32220  // shared boundaries
32221  if (this->is_mesh_distributed())
32222  {
32223  // Get the rank of the current processor
32224  const unsigned my_rank = this->communicator_pt()->my_rank();
32225 
32226  // Get the number of shared curves in the current processor
32227  const unsigned n_shared_curves =
32228  this->nshared_boundary_curves(my_rank);
32229 
32230  // Loop over the shared curves
32231  for (unsigned i = 0; i < n_shared_curves; i ++)
32232  {
32233  // Get the number of polylines associated to the current shared
32234  // curve
32235  const unsigned n_polyline =
32236  this->nshared_boundary_polyline(my_rank, i);
32237 
32238  // Loop over the polylines associated to the current shared
32239  // curve
32240  for (unsigned p = 0; p < n_polyline; p++)
32241  {
32242  // Get a temporary representation of the shared polyline
32243  TriangleMeshPolyLine* tmp_polyline_pt =
32244  this->shared_boundary_polyline_pt(my_rank, i, p);
32245 
32246  // Is the initial vertex connected?
32247  if (tmp_polyline_pt->is_initial_vertex_connected())
32248  {
32249  // Get the boundary id of the current polyline
32250  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32251 
32252  // Boundary id to which the curve is connected
32253  const unsigned dst_bnd_id =
32254  tmp_polyline_pt->initial_vertex_connected_bnd_id();
32255 
32256  // Boundary chunk to which the curve is connected
32257  const unsigned dst_chunk =
32258  tmp_polyline_pt->initial_vertex_connected_n_chunk();
32259 
32260  // Get the nodes representation of the current boundary
32261  Vector<Vector<Node*> > src_bnd_node_pt =
32262  bnd_sorted_segment_node_pt[bnd_id];
32263 
32264  // Get the nodes representation of the boundary to connect
32265  Vector<Vector<Node*> > dst_bnd_node_pt =
32266  bnd_sorted_segment_node_pt[dst_bnd_id];
32267 
32268  // Add the repeated node to the list of non delete-able
32269  // vertices
32270  add_non_delete_vertices_from_boundary_helper(
32271  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32272 
32273  } // if (tmp_polyline_pt->is_initial_vertex_connected())
32274 
32275  // Is the final vertex connected?
32276  if (tmp_polyline_pt->is_final_vertex_connected())
32277  {
32278  // Get the boundary id of the current polyline
32279  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32280 
32281  // Boundary id to which the curve is connected
32282  const unsigned dst_bnd_id =
32283  tmp_polyline_pt->final_vertex_connected_bnd_id();
32284 
32285  // Boundary chunk to which the curve is connected
32286  const unsigned dst_chunk =
32287  tmp_polyline_pt->final_vertex_connected_n_chunk();
32288 
32289  // Get the nodes representation of the current boundary
32290  Vector<Vector<Node*> > src_bnd_node_pt =
32291  bnd_sorted_segment_node_pt[bnd_id];
32292 
32293  // Get the nodes representation of the boundary to connect
32294  Vector<Vector<Node*> > dst_bnd_node_pt =
32295  bnd_sorted_segment_node_pt[dst_bnd_id];
32296 
32297  // Add the repeated node to the list of non delete-able
32298  // vertices
32299  add_non_delete_vertices_from_boundary_helper(
32300  src_bnd_node_pt, dst_bnd_node_pt, dst_bnd_id, dst_chunk);
32301 
32302  } // if (tmp_polyline_pt->is_final_vertex_connected())
32303 
32304  } // for (p < n_polyline)
32305 
32306  } // for (i < n_shared_curves)
32307 
32308  } // if (this->is_mesh_distributed())
32309 
32310 #endif // #ifdef OOMPH_HAS_MPI
32311 
32312  }
32313 
32314  //=========================================================================
32315  /// \short Adds the vertices from the sources boundary that are
32316  /// repeated in the destination boundary to the list of non
32317  /// delete-able vertices in the destination boundary
32318  //=========================================================================
32319  template<class ELEMENT>
32322  Vector<Vector<Node*> > src_bound_segment_node_pt,
32323  Vector<Vector<Node*> > dst_bound_segment_node_pt,
32324  const unsigned &dst_bnd_id, const unsigned &dst_bnd_chunk)
32325  {
32326  // Get the number of segments in the source boundary
32327  const unsigned n_seg = src_bound_segment_node_pt.size();
32328  // Loop over the segments in the source boundary
32329  for (unsigned iseg = 0; iseg < n_seg; iseg++)
32330  {
32331  // Get the number of nodes in the current segment
32332  const unsigned nnode = src_bound_segment_node_pt[iseg].size();
32333  // Get the left and right node of the current segment
32334  Node* left_node_pt = src_bound_segment_node_pt[iseg][0];
32335  Node* right_node_pt = src_bound_segment_node_pt[iseg][nnode-1];
32336 
32337  // Get the number of segments in the destination boundary
32338  const unsigned n_dst_seg = dst_bound_segment_node_pt.size();
32339  // Loop over the segments in the destination boundary
32340  for (unsigned jseg = 0; jseg < n_dst_seg; jseg++)
32341  {
32342  // Get the number of nodes on the current destination segment
32343  const unsigned n_dst_node = dst_bound_segment_node_pt[jseg].size();
32344  // Loop over the nodes until the node has been found or we have
32345  // visited all the nodes
32346  for (unsigned jnode = 0; jnode < n_dst_node; jnode++)
32347  {
32348  // Get a pointer to the jnode in the destination segment
32349  // boundary
32350  Node* tmp_node_pt = dst_bound_segment_node_pt[jseg][jnode];
32351  // Is the node the same as the left or right node if
32352  // the source segment boundary
32353  if (tmp_node_pt == left_node_pt)
32354  {
32355  // We have foud the node to connect, get the vertex of the node
32356  Vector<double> vertex(2);
32357  vertex[0] = tmp_node_pt->x(0);
32358  vertex[1] = tmp_node_pt->x(1);
32359 
32360  // Establish the vertex coordinate as untouchable in the
32361  // destination boundary during the adaptation process. It
32362  // means that unrefinement can not take off the vertices
32363  // that receive connections in the destination boundary
32364  Boundary_connections_pt[dst_bnd_id].insert(vertex);
32365  //Boundary_chunk_connections_pt[dst_bnd_id][dst_bnd_chunk].
32366  // insert(vertex);
32367 
32368  // return
32369  return;
32370 
32371  } // if (tmp_node_pt == left_node_pt)
32372  else if (tmp_node_pt == right_node_pt)
32373  {
32374  // We have foud the node to connect, get the vertex of the node
32375  Vector<double> vertex(2);
32376  vertex[0] = tmp_node_pt->x(0);
32377  vertex[1] = tmp_node_pt->x(1);
32378 
32379  // Establish the vertex coordinate as untouchable in the
32380  // destination boundary during the adaptation process. It
32381  // means that unrefinement can not take off the vertices
32382  // that receive connections in the destination boundary
32383  //Boundary_chunk_connections_pt[dst_bnd_id][dst_bnd_chunk].
32384  // insert(vertex);
32385  Boundary_connections_pt[dst_bnd_id].insert(vertex);
32386 
32387  // return
32388  return;
32389 
32390  } // else if (tmp_node_pt == right_node_pt)
32391 
32392  } // for (jnode < n_dst_node)
32393 
32394  } // for (jseg < n_dst_seg)
32395 
32396  } // for (iseg < n_seg)
32397 
32398  }
32399 
32400 #ifdef OOMPH_HAS_MPI
32401  //=========================================================================
32402  /// \short Synchronise the vertices that are marked for non deletion
32403  // on the shared boundaries. Unrefinement of shared boundaries is
32404  // performed only if the candidate node is not marked for non deletion
32405  //=========================================================================
32406  template<class ELEMENT>
32409  {
32410  // Get the number of processors
32411  const unsigned nproc = this->communicator_pt()->nproc();
32412  // Get my rank
32413  const unsigned my_rank = this->communicator_pt()->my_rank();
32414 
32415  // loop over the processors
32416  for (unsigned jproc = 0; jproc < nproc; jproc++)
32417  {
32418  // The number of boundaries shared with the current processor
32419  // (if jproc==my_rank then there are no shared boundaries
32420  // between them)
32421  const unsigned n_shd_bnd_jproc =
32422  this->nshared_boundaries(my_rank, jproc);
32423 
32424  // Are there shared boundaries with the jproc processor?
32425  // There are no info. with myself
32426  if (jproc != my_rank && n_shd_bnd_jproc > 0)
32427  {
32428  // Storage for the boundaries ids with vertices for non
32429  // deletion
32430  Vector<unsigned> shd_bnd_id_for_non_deletion;
32431 
32432  // Storage for chunk numbers of boundaries with vertices
32433  // for non deletion
32434  Vector<unsigned> chunk_for_non_deletion;
32435 
32436  // The number of vertices for nondeletion in the shared
32437  // boundaries
32438  Vector<unsigned> number_vertices_non_deletion;
32439 
32440  // Vertices marked for nondeletion in shared boundaries
32441  Vector<Vector<Vector<double> > > vertices_for_non_deletion;
32442 
32443  // Get the boundary ids of the shared boundaries with jproc
32444  // processor
32445  Vector<unsigned> shd_bnd_ids =
32446  this->shared_boundaries_ids(my_rank, jproc);
32447 
32448  // Get the number of shared boundaries with jproc
32449  const unsigned n_shd_bnd_jproc = shd_bnd_ids.size();
32450  // loop over the shared boundaries with jproc
32451  for (unsigned ishd_bnd=0;ishd_bnd<n_shd_bnd_jproc;ishd_bnd++)
32452  {
32453  // Get the shared boudary id
32454  const unsigned shd_bnd_id = shd_bnd_ids[ishd_bnd];
32455  // Get the associated polyline
32456  TriangleMeshPolyLine *shd_polyline_pt =
32457  this->boundary_polyline_pt(shd_bnd_id);
32458  // Get the chunk number
32459  const unsigned chunk = shd_polyline_pt->boundary_chunk();
32460 
32461  // Store the vertices not allowed for deletion
32462  std::set<Vector<double> > no_delete_vertex;
32463 
32464  // Does the boundary has vertives for nondeleteion?
32465  const bool boundary_receive_connections =
32466  this->boundary_connections(shd_bnd_id, chunk,
32467  no_delete_vertex);
32468 
32469  // Get the number of vertices for nondeletion
32470  const unsigned n_non_delete_vertex = no_delete_vertex.size();
32471 
32472  // Are there vertices for nondeletion?
32473  if (boundary_receive_connections && n_non_delete_vertex > 0)
32474  {
32475  // Add the shared boundary id
32476  shd_bnd_id_for_non_deletion.push_back(shd_bnd_id);
32477  // Add the chunk number
32478  chunk_for_non_deletion.push_back(chunk);
32479  // Add the number of vertices for non deletion
32480  number_vertices_non_deletion.push_back(n_non_delete_vertex);
32481 
32482  // The list of vertices to add
32483  Vector<Vector<double> > tmp_vertices;
32484 
32485  // Add the vertices for non deletion
32486  for (std::set<Vector<double> >::iterator it =
32487  no_delete_vertex.begin();
32488  it != no_delete_vertex.end(); it++)
32489  {
32490  // Get the vertex coordinate
32491  Vector<double> vertex = (*it);
32492  tmp_vertices.push_back(vertex);
32493  }
32494 
32495  // Add the vertices coordinates to a vector storage
32496  vertices_for_non_deletion.push_back(tmp_vertices);
32497 
32498  } // if (boundary_receive_connections && n_non_delete_vertex > 0)
32499 
32500  } // for (ishd_bnd<n_shd_bnd_jproc)
32501 
32502  // ----------------------------------------------------------
32503  // ----------------------------------------------------------
32504  // ----------------------------------------------------------
32505  // Now send the info. to the other processor (jproc)
32506  // ----------------------------------------------------------
32507  // ----------------------------------------------------------
32508  // ----------------------------------------------------------
32509  // Get the communicator of the mesh
32510  OomphCommunicator* comm_pt = this->communicator_pt();
32511 
32512  // Set MPI info
32513  MPI_Status status;
32514  MPI_Request request;
32515 
32516  // -----------------------------------------------------------
32517  // Prepare the data
32518  // Get the number of shared boundaires with vertices marked
32519  // for non deletion
32520  const unsigned n_shd_bnd_with_non_delete_vertices =
32521  shd_bnd_id_for_non_deletion.size();
32522 
32523  // Size of the package
32524  const unsigned size_package = 3;
32525  // Ndata to send
32526  const unsigned n_unsigned_data_to_send =
32527  n_shd_bnd_with_non_delete_vertices*size_package;
32528  // The flat package to send the info.
32529  Vector<unsigned> flat_package_unsigned_send(n_unsigned_data_to_send);
32530  Vector<double> flat_package_double_send;
32531 
32532  Vector<unsigned> flat_package_unsigned_recv;
32533  Vector<double> flat_package_double_recv;
32534 
32535  // Prepare the data to be sent
32536  unsigned j=0;
32537  for (unsigned i=0;i<n_shd_bnd_with_non_delete_vertices;i++)
32538  {
32539  // The shared boundary id
32540  flat_package_unsigned_send[j++] =
32541  shd_bnd_id_for_non_deletion[i];
32542  // The chunk number
32543  flat_package_unsigned_send[j++] =
32544  chunk_for_non_deletion[i];
32545  // The number of vertices for nondeletion
32546  flat_package_unsigned_send[j++] =
32547  number_vertices_non_deletion[i];
32548  // Also package the vertices
32549  const unsigned n_vertices_non_deletion =
32550  number_vertices_non_deletion[i];
32551  // Loop over the vertices and store them in the flat
32552  // package to be sent
32553  for (unsigned h=0;h<n_vertices_non_deletion;h++)
32554  {
32555  flat_package_double_send.push_back(
32556  vertices_for_non_deletion[i][h][0]);
32557  flat_package_double_send.push_back(
32558  vertices_for_non_deletion[i][h][1]);
32559  } // for (h<n_vertices_non_deletion)
32560 
32561  } // for (i<n_shd_bnd_with_non_delete_vertices)
32562 
32563  // ----------------------------------------------------------
32564  int send_proc = jproc;
32565  int recv_proc = jproc;
32566  unsigned send_count_unsigned_values = n_unsigned_data_to_send;
32567  unsigned send_count_double_values = flat_package_double_send.size();
32568  //-----------------------------------------------------------
32569  // Do the transfering of info.
32570  //-----------------------------------------------------------
32571  // Start with UNSIGNED info.
32572  MPI_Isend(&send_count_unsigned_values,1,MPI_UNSIGNED,
32573  send_proc,1,comm_pt->mpi_comm(),&request);
32574 
32575  unsigned receive_count_unsigned_values=0;
32576  MPI_Recv(&receive_count_unsigned_values,1,MPI_UNSIGNED,
32577  recv_proc,1,comm_pt->mpi_comm(),&status);
32578 
32579  MPI_Wait(&request,MPI_STATUS_IGNORE);
32580 
32581  // Send the actual data
32582  if (send_count_unsigned_values!=0)
32583  {
32584  MPI_Isend(&flat_package_unsigned_send[0],
32585  send_count_unsigned_values,MPI_UNSIGNED,
32586  send_proc,2,comm_pt->mpi_comm(),&request);
32587  }
32588 
32589  // Receive the actual data
32590  if (receive_count_unsigned_values!=0)
32591  {
32592  flat_package_unsigned_recv.resize(receive_count_unsigned_values);
32593  MPI_Recv(&flat_package_unsigned_recv[0],
32594  receive_count_unsigned_values,
32595  MPI_UNSIGNED,recv_proc,2,comm_pt->mpi_comm(),&status);
32596  }
32597 
32598  // Wait for sending the data and the other processor
32599  // receives
32600  if (send_count_unsigned_values!=0)
32601  {
32602  MPI_Wait(&request,MPI_STATUS_IGNORE);
32603  }
32604 
32605  //-----------------------------------------------------------
32606  // Then continue with DOUBLE info.
32607  MPI_Isend(&send_count_double_values,1,MPI_UNSIGNED,
32608  send_proc,1,comm_pt->mpi_comm(),&request);
32609 
32610  unsigned receive_count_double_values=0;
32611  MPI_Recv(&receive_count_double_values,1,MPI_UNSIGNED,
32612  recv_proc,1,comm_pt->mpi_comm(),&status);
32613 
32614  MPI_Wait(&request,MPI_STATUS_IGNORE);
32615 
32616  // Send the actual data
32617  if (send_count_double_values!=0)
32618  {
32619  MPI_Isend(&flat_package_double_send[0],
32620  send_count_double_values,MPI_DOUBLE,
32621  send_proc,2,comm_pt->mpi_comm(),&request);
32622  }
32623 
32624  // Receive the actual data
32625  if (receive_count_double_values!=0)
32626  {
32627  flat_package_double_recv.resize(receive_count_double_values);
32628  MPI_Recv(&flat_package_double_recv[0],
32629  receive_count_double_values,
32630  MPI_DOUBLE,recv_proc,2,comm_pt->mpi_comm(),&status);
32631  }
32632 
32633  // Wait for sending the data and the other processor
32634  // receives
32635  if (send_count_double_values!=0)
32636  {
32637  MPI_Wait(&request,MPI_STATUS_IGNORE);
32638  }
32639 
32640  // ------------------------------------------------------------
32641  // ------------------------------------------------------------
32642  // ------------------------------------------------------------
32643  // Now unpackage the data
32644  // ------------------------------------------------------------
32645  // ------------------------------------------------------------
32646  // ------------------------------------------------------------
32647 
32648  // Storage for the boundaries ids with vertices for non
32649  // deletion
32650  Vector<unsigned> recv_shd_bnd_id_for_non_deletion;
32651 
32652  // Storage for chunk numbers of boundaries with vertices
32653  // for non deletion
32654  Vector<unsigned> recv_chunk_for_non_deletion;
32655 
32656  // The number of vertices for nondeletion in the shared
32657  // boundaries
32658  Vector<unsigned> recv_number_vertices_non_deletion;
32659 
32660  // Vertices marked for nondeletion in shared boundaries
32661  Vector<Vector<Vector<double> > > recv_vertices_for_non_deletion;
32662 
32663  // Counter
32664  j = 0;
32665  for (unsigned i=0;i<receive_count_unsigned_values;i+=3)
32666  {
32667  // Get the shared boundary id
32668  const unsigned recv_shd_bnd_id =
32669  flat_package_unsigned_recv[i];
32670  recv_shd_bnd_id_for_non_deletion.push_back(recv_shd_bnd_id);
32671  // Get the chunk number
32672  const unsigned recv_chunk =
32673  flat_package_unsigned_recv[i+1];
32674  recv_chunk_for_non_deletion.push_back(recv_chunk);
32675  // Get the number of vertices for non deletion
32676  const unsigned recv_num_vertices =
32677  flat_package_unsigned_recv[i+2];
32678  recv_number_vertices_non_deletion.push_back(recv_num_vertices);
32679 
32680  // Create a temporal storage
32681  Vector<Vector<double> > temp_recv_vertices;
32682  // Now get the vertices
32683  for (unsigned h=0;h<recv_num_vertices;h++)
32684  {
32685  Vector<double> tmp_vertex(2);
32686  tmp_vertex[0] = flat_package_double_recv[j++];
32687  tmp_vertex[1] = flat_package_double_recv[j++];
32688  // Add the vertex to the vector of vertices
32689  temp_recv_vertices.push_back(tmp_vertex);
32690  } // for (h<recv_num_vertices)
32691 
32692  // Add the vertices to the vector of vertices
32693  recv_vertices_for_non_deletion.push_back(temp_recv_vertices);
32694 
32695  } // for(i<receive_count_unsigned_values)
32696 
32697  // ---------------------------------------------------------
32698  // ---------------------------------------------------------
32699  // ---------------------------------------------------------
32700  // Now add the vertices to the data structures to mark them
32701  // as non delete-able
32702  // ---------------------------------------------------------
32703  // ---------------------------------------------------------
32704  // ---------------------------------------------------------
32705 
32706  // Get the number of shd boundaries that have vertices
32707  // marked for non deletion
32708  const unsigned n_recv_shd_bnd_id_for_non_deletion =
32709  recv_shd_bnd_id_for_non_deletion.size();
32710  // loop over the shared boundaries and add the data for non
32711  // deletion
32712  for (unsigned i=0;i<n_recv_shd_bnd_id_for_non_deletion;i++)
32713  {
32714  // Get the shared boundary id.
32715  const unsigned shd_bnd_id =
32716  recv_shd_bnd_id_for_non_deletion[i];
32717  // Get the chunk number
32718  unsigned chunk = recv_chunk_for_non_deletion[i];
32719  // Increase and decrease the chunk number to avoid the
32720  // warning when compiling without PARANOID
32721  chunk++;
32722  chunk--;
32723 
32724  // Get the number of vertices marked for non deletion
32725  const unsigned n_vertices =
32726  recv_number_vertices_non_deletion[i];
32727  // Add all the vertices
32728  for (unsigned h=0;h<n_vertices;h++)
32729  {
32730  // Get the vertex
32731  Vector<double> vertex(2);
32732  vertex[0] = recv_vertices_for_non_deletion[i][h][0];
32733  vertex[1] = recv_vertices_for_non_deletion[i][h][1];
32734  // Add the vertex to the data structure for non
32735  // deletion
32736  //Boundary_chunk_connections_pt[shd_bnd_id][chunk].
32737  // insert(vertex);
32738  Boundary_connections_pt[shd_bnd_id].insert(vertex);
32739 
32740  } // for (h<n_vertices)
32741 
32742  } // for (i<n_recv_shd_bnd_id_for_non_deletion)
32743 
32744  } // if (jproc != my_rank && n_shd_bnd_jproc > 0)
32745 
32746  } // for (jproc < nproc)
32747 
32748  }
32749 #endif // #ifdef OOMPH_HAS_MPI
32750 
32751  //=========================================================================
32752  /// \short After unrefinement and refinement has taken place compute
32753  /// the new vertices numbers of the temporary representation of the
32754  // boundaries to connect.
32755  //=========================================================================
32756  template<class ELEMENT>
32758  Vector<TriangleMeshPolygon *> &tmp_outer_polygons_pt,
32759  Vector<TriangleMeshOpenCurve *> &tmp_open_curves_pt)
32760  {
32761  // Dummy storages
32762  Vector<TriangleMeshPolyLine*> dummy_resume_initial_connection_polyline_pt;
32763  Vector<TriangleMeshPolyLine*> dummy_resume_final_connection_polyline_pt;
32764 
32765  // Clear the storage
32766  dummy_resume_initial_connection_polyline_pt.clear();
32767  dummy_resume_final_connection_polyline_pt.clear();
32768 
32769  // Get the initial shared boundary id (to check whether the
32770  // polylines represent original or shared boundaries)
32771  const unsigned init_shd_bnd_id = this->initial_shared_boundary_id();
32772 
32773  // ------------------------------------------------------------------
32774  // This seems unnecesary since the outer polygons does not create
32775  // connections with other boundaries (the original ones)
32776  // ------------------------------------------------------------------
32777  // Unnecessary?
32778  // ------------------------------------------------------------------
32779 
32780  // Loop over the temporary outer polygons create the connection
32781  // information of those boundaries marked to be connected at their
32782  // ends
32783 
32784  // ------------------------------------------------------------------
32785  // Temporary outer polygons
32786  // ------------------------------------------------------------------
32787 
32788  // Get the number of outer boundaries (closed boundaries)
32789  const unsigned n_outer_boundaries = tmp_outer_polygons_pt.size();
32790 
32791  // Loop over the outer boundaries
32792  for (unsigned i = 0; i < n_outer_boundaries; i++)
32793  {
32794  // Get a temporary polygon representation
32795  TriangleMeshPolygon* tmp_polygon_pt = tmp_outer_polygons_pt[i];
32796  // Get the number of polylines associated to the current outer
32797  // boundary
32798  const unsigned n_polyline = tmp_polygon_pt->npolyline();
32799  // Loop over the polylines
32800  for (unsigned p = 0; p < n_polyline; p++)
32801  {
32802  // Get a temporary representation of the polyline
32803  TriangleMeshPolyLine* tmp_polyline_pt =
32804  tmp_polygon_pt->polyline_pt(p);
32805 
32806  // Get the boundary id
32807  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32808 
32809  // Is the boundary to connect a shared boundary
32810  if (bnd_id < init_shd_bnd_id)
32811  {
32812  // Restore the connections of the current polyline
32813  restore_polyline_connections_helper(
32814  tmp_polyline_pt,
32815  dummy_resume_initial_connection_polyline_pt,
32816  dummy_resume_final_connection_polyline_pt);
32817 
32818  } // if (bnd_id < init_shd_bnd_id)
32819 
32820  } // for (p < n_polyline)
32821 
32822  } // for (i < n_outer_boundaries)
32823 
32824  // ------------------------------------------------------------------
32825  // Unnecessary?
32826  // ------------------------------------------------------------------
32827 
32828  // ------------------------------------------------------------------
32829  // Temporary open boundaries (nonclosed internal boundaries)
32830  // ------------------------------------------------------------------
32831 
32832  // Get the number of internal boundaries (open boundaries)
32833  const unsigned n_open_boundaries = tmp_open_curves_pt.size();
32834 
32835  // Loop over the internal open boundaries
32836  for (unsigned i = 0; i < n_open_boundaries; i++)
32837  {
32838  // Get a temporary representation for the open curve
32839  TriangleMeshOpenCurve* tmp_open_curve_pt = tmp_open_curves_pt[i];
32840 
32841  // Get the number of curve sections associated to the current
32842  // internal open boundary
32843  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
32844 
32845  // Loop over the curve section
32846  for (unsigned p = 0; p < n_curve_section; p++)
32847  {
32848  // Get a temporary representation of the curve section
32849  // (polyline)
32850  TriangleMeshPolyLine* tmp_polyline_pt =
32851  tmp_open_curve_pt->polyline_pt(p);
32852 
32853  // Get the boundary id
32854  const unsigned bnd_id = tmp_polyline_pt->boundary_id();
32855 
32856  // Is the boundary to connect a shared boundary
32857  if (bnd_id < init_shd_bnd_id)
32858  {
32859  // Restore the connections of the current polyline
32860  restore_polyline_connections_helper(
32861  tmp_polyline_pt,
32862  dummy_resume_initial_connection_polyline_pt,
32863  dummy_resume_final_connection_polyline_pt);
32864 
32865  } // if (bnd_id < init_shd_bnd_id)
32866 
32867  } // for (p < n_curve_section)
32868 
32869  } // for (i < n_open_boundaries)
32870 
32871  }
32872 
32873  //=========================================================================
32874  /// \short After unrefinement and refinement has taken place compute
32875  /// the new vertices numbers of the boundaries to connect (in a
32876  /// distributed scheme it may be possible that the destination
32877  /// boundary does no longer exist, therefore the connection is
32878  /// suspended. It is not permanently deleted because if load balance
32879  /// takes place it may be possible that the boundary to connect be
32880  /// part of the new domain representation, so the connection would
32881  /// exist)
32882  //=========================================================================
32883  template<class ELEMENT>
32885  Vector<TriangleMeshPolyLine*> &resume_initial_connection_polyline_pt,
32886  Vector<TriangleMeshPolyLine*> &resume_final_connection_polyline_pt)
32887  {
32888  // Clear the storage
32889  resume_initial_connection_polyline_pt.clear();
32890  resume_final_connection_polyline_pt.clear();
32891 
32892  // Loop over the boundaries in the domain (outer, internal -- closed
32893  // and open) and restore the connection information of those
32894  // boundaries marked to be connected at their ends
32895 
32896  // ------------------------------------------------------------------
32897  // Outer boundaries
32898  // ------------------------------------------------------------------
32899 
32900  // Get the number of outer boundaries (closed boundaries)
32901  const unsigned n_outer_boundaries = this->Outer_boundary_pt.size();
32902 
32903  // Loop over the outer boundaries
32904  for (unsigned i = 0; i < n_outer_boundaries; i++)
32905  {
32906  // Get a temporary polygon representation
32907  TriangleMeshPolygon* tmp_polygon_pt = this->Outer_boundary_pt[i];
32908  // Get the number of polylines associated to the current outer
32909  // boundary
32910  const unsigned n_polyline = tmp_polygon_pt->npolyline();
32911  // Loop over the polylines
32912  for (unsigned p = 0; p < n_polyline; p++)
32913  {
32914  // Get a temporary representation of the polyline
32915  TriangleMeshPolyLine* tmp_polyline_pt =
32916  tmp_polygon_pt->polyline_pt(p);
32917 
32918  // Restore the connections of the current polyline
32919  restore_polyline_connections_helper(
32920  tmp_polyline_pt,
32921  resume_initial_connection_polyline_pt,
32922  resume_final_connection_polyline_pt);
32923 
32924  } // for (p < n_polyline)
32925 
32926  } // for (i < n_outer_boundaries)
32927 
32928  // ------------------------------------------------------------------
32929  // Internal boundaries
32930  // ------------------------------------------------------------------
32931 
32932  // Get the number of internal boundaries (closed boundaries)
32933  const unsigned n_internal_boundaries = this->Internal_polygon_pt.size();
32934 
32935  // Loop over the internal boundaries
32936  for (unsigned i = 0; i < n_internal_boundaries; i++)
32937  {
32938  // Get a temporary polygon representation
32939  TriangleMeshPolygon* tmp_polygon_pt = this->Internal_polygon_pt[i];
32940  // Get the number of polylines associated to the current internal
32941  // boundary
32942  const unsigned n_polyline = tmp_polygon_pt->npolyline();
32943  // Loop over the polylines
32944  for (unsigned p = 0; p < n_polyline; p++)
32945  {
32946  // Get a temporary representation of the polyline
32947  TriangleMeshPolyLine* tmp_polyline_pt =
32948  tmp_polygon_pt->polyline_pt(p);
32949 
32950  // Restore the connections of the current polyline
32951  restore_polyline_connections_helper(
32952  tmp_polyline_pt,
32953  resume_initial_connection_polyline_pt,
32954  resume_final_connection_polyline_pt);
32955 
32956  } // for (p < n_polyline)
32957 
32958  } // for (i < n_internal_boundaries)
32959 
32960  // ------------------------------------------------------------------
32961  // Open boundaries (nonclosed internal boundaries)
32962  // ------------------------------------------------------------------
32963 
32964  // Get the number of internal boundaries (open boundaries)
32965  const unsigned n_open_boundaries = this->Internal_open_curve_pt.size();
32966 
32967  // Loop over the internal open boundaries
32968  for (unsigned i = 0; i < n_open_boundaries; i++)
32969  {
32970  // Get a temporary representation for the open curve
32971  TriangleMeshOpenCurve* tmp_open_curve_pt =
32972  this->Internal_open_curve_pt[i];
32973 
32974  // Get the number of curve sections associated to the current
32975  // internal open boundary
32976  const unsigned n_curve_section = tmp_open_curve_pt->ncurve_section();
32977 
32978  // Loop over the curve section
32979  for (unsigned p = 0; p < n_curve_section; p++)
32980  {
32981  // Get a temporary representation of the curve section
32982  // (polyline)
32983  TriangleMeshPolyLine* tmp_polyline_pt =
32984  tmp_open_curve_pt->polyline_pt(p);
32985 
32986  // Restore the connections of the current polyline
32987  restore_polyline_connections_helper(
32988  tmp_polyline_pt,
32989  resume_initial_connection_polyline_pt,
32990  resume_final_connection_polyline_pt);
32991 
32992  } // for (p < n_curve_section)
32993 
32994  } // for (i < n_open_boundaries)
32995 
32996  }
32997 
32998  //=========================================================================
32999  /// \short Restore the connections of the specific polyline
33000  /// The vertices numbering on the destination boundaries may have
33001  /// change because of (un)refinement in the destination boundaries.
33002  /// Also deals with connection that do not longer exist because the
33003  /// destination boundary does no longer exist because of the distribution
33004  /// process
33005  //=========================================================================
33006  template<class ELEMENT>
33009  TriangleMeshPolyLine* polyline_pt,
33010  Vector<TriangleMeshPolyLine*> &resume_initial_connection_polyline_pt,
33011  Vector<TriangleMeshPolyLine*> &resume_final_connection_polyline_pt)
33012  {
33013  // If the polyline is connected at any of its ends compute the new
33014  // vertex number on the destination boundary
33015 
33016  // ------------------------------------------------------------------
33017  // Is the initial vertex connected?
33018  if (polyline_pt->is_initial_vertex_connected())
33019  {
33020  // The pointer to the boundary to connect
33021  TriangleMeshPolyLine *poly_to_connect_pt = 0;
33022 
33023  // Get the boundary id of the destination/connected boundary
33024  const unsigned dst_bnd_id_initial =
33025  polyline_pt->initial_vertex_connected_bnd_id();
33026 
33027  // Get the initial vertex on the current boundary
33028  Vector<double> src_vertex_coordinates_initial =
33029  polyline_pt->vertex_coordinate(0);
33030 
33031 #ifdef PARANOID
33032  // Is the mesh distributed?
33033 #ifdef OOMPH_HAS_MPI
33034  if (this->is_mesh_distributed())
33035  {
33036  // Get the initial shared boundary id
33037  const unsigned init_shd_bnd_id =
33038  this->initial_shared_boundary_id();
33039  // Is the boundary to connect a shared boundary
33040  if (dst_bnd_id_initial >= init_shd_bnd_id)
33041  {
33042  // Get the current polyline original boundary id
33043  const unsigned bnd_id = polyline_pt->boundary_id();
33044  std::ostringstream error_message;
33045  error_message
33046  << "INITIAL VERTEX CONNECTION\n"
33047  << "The current original boundary is trying to connect to a\n"
33048  << "shared boundary, this is not allowed. In this case the\n"
33049  << "shared boundary should be the one that connects with the\n"
33050  << "original boundary\n"
33051  << "The current original boundary (" << bnd_id << ") is marked\n"
33052  << "to have a connection at the\nINITIAL vertex ("
33053  << src_vertex_coordinates_initial[0] << ","
33054  << src_vertex_coordinates_initial[1] << ")\n"
33055  << "with the shared boundary ("<< dst_bnd_id_initial << ")\n"
33056  << "This is the list of vertices on the shared destination boundary\n";
33057  // Get the pointer to the associated polyline by using the
33058  // boundary id
33059  TriangleMeshPolyLine *dst_polyline =
33060  this->boundary_polyline_pt(dst_bnd_id_initial);
33061  // The number of vertices on the destination boundary
33062  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
33063  // Loop over the vertices print them
33064  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
33065  {
33066  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
33067  error_message
33068  << "Vertex#(i): ("
33069  << current_vertex[0] << ", " << current_vertex[1] << ")\n";
33070  }
33071  throw OomphLibError(
33072  error_message.str(),
33073  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33074  OOMPH_EXCEPTION_LOCATION);
33075  } // if (dst_bnd_id_initial >= init_shd_bnd_id)
33076 
33077  } // if (this->is_mesh_distributed())
33078 #endif // #ifdef OOMPH_HAS_MPI
33079 
33080 #endif // #ifdef PARANOID
33081 
33082  // Flag to indicate if the vertex was found on the destination
33083  // boundary
33084  bool found_vertex_on_dst_boundary_initial = false;
33085 
33086  // Flag that stores the chunk number to connect (only used in
33087  // distributed meshes)
33088  unsigned sub_poly_to_connect = 0;
33089 
33090  // Store the vertex number on the destination boundary
33091  unsigned n_vertex_connection_initial = 0;
33092 
33093  // Flags only used in a distributed mesh
33094  // ----------------------------------------
33095  // Flag to indicate we are trying to connect to an split boundary
33096  bool connecting_to_an_split_boundary = false;
33097 
33098  // Flag to indicate we are trying to connecto to an internal
33099  // boundary that is overlaped by a shared boundary)
33100  bool connecting_to_an_overlaped_boundary = false;
33101 
33102 #ifdef OOMPH_HAS_MPI
33103  if (this->is_mesh_distributed())
33104  {
33105  // We can only connect to an original boundary, check if the
33106  // boundary was splitted during the distribution process to
33107  // consider all the chunks (sub-polylines) of the boundary
33108  if (this->boundary_was_splitted(dst_bnd_id_initial))
33109  {
33110  connecting_to_an_split_boundary = true;
33111  } // if (this->boundary_was_splitted(dst_bnd_id_initial))
33112 
33113  // Check if the destination boundary, or any of its chunks is
33114  // marked to be overlapped by a shared boundary, if that is the
33115  // case we can only connect to the chunks that are not
33116  // overlapped by shared boundaries (the shared boundaries are in
33117  // charge of generating the connections with original boundaries
33118  // and with themselves)
33119  if (connecting_to_an_split_boundary)
33120  {
33121  // Get the number of chucks that represent the destination
33122  // boundary
33123  const unsigned n_sub_poly =
33124  this->nboundary_subpolylines(dst_bnd_id_initial);
33125  // Now loop over the chunks of the destination boundary and if
33126  // any of them is marked to be overlaped by a shared boundary
33127  // then set the flag and break the loop
33128  for (unsigned ii =0; ii < n_sub_poly; ii++)
33129  {
33130  if (this->
33131  boundary_marked_as_shared_boundary(dst_bnd_id_initial, ii))
33132  {
33133  // Mark the boundary as being overlaped by a shared
33134  // boundary
33135  connecting_to_an_overlaped_boundary = true;
33136  // Break, no need to look for more overlapings
33137  break;
33138  } // if (boundary_marked_as_shared_boundary(...))
33139  } // for (ii < n_sub_poly)
33140  } // if (connecting_to_an_split_boundary)
33141  else
33142  {
33143  // If not connecting to an split boundary then check if the
33144  // whole destination boundary is overlaped by an internal
33145  // boundary
33146  if (this->
33147  boundary_marked_as_shared_boundary(dst_bnd_id_initial, 0))
33148  {
33149  // Mark the boundary as being overlaped by a shared boundary
33150  connecting_to_an_overlaped_boundary = true;
33151  } // if (boundary_marked_as_shared_boundary(...))
33152  } // else if (connecting_to_an_split_boundary)
33153 
33154  } // if (this->is_mesh_distributed())
33155 
33156 #endif // #ifdef OOMPH_HAS_MPI
33157 
33158  // If we are connecting neither to an split boundary nor an
33159  // overlaped boundary then get the pointer to the original
33160  // boundary
33161  if (!(connecting_to_an_split_boundary ||
33162  connecting_to_an_overlaped_boundary))
33163  {
33164  // Get the polyline pointer representing the destination
33165  // boundary
33166  poly_to_connect_pt = this->boundary_polyline_pt(dst_bnd_id_initial);
33167  } // else if (NOT split, NOT overlaped)
33168 
33169  // Now look for the vertex number on the destination boundary(ies)
33170  // -- in case that the boundary was split ---
33171 
33172  // Do not check for same orientation, that was previously worked
33173  // by interchanging the connections boundaries (if necessary)
33174 
33175  // If the boundary was not split then ...
33176  if (!connecting_to_an_split_boundary)
33177  {
33178  // ... check if the boundary is marked to be overlaped by
33179  // a shared boundary
33180  if (!connecting_to_an_overlaped_boundary)
33181  {
33182  // If that is not the case then we can safely look for the
33183  // vertex number on the destination boundary
33184  found_vertex_on_dst_boundary_initial =
33185  this->get_connected_vertex_number_on_destination_polyline(
33186  poly_to_connect_pt,
33187  src_vertex_coordinates_initial,
33188  n_vertex_connection_initial);
33189 
33190  } // if (!connecting_to_an_overlaped_boundary)
33191  else
33192  {
33193  // If the whole boundary is marked to be overlaped by a shared
33194  // boundary then do nothing, the shared boundaries are already
33195  // in charge of performing the connection (it will be required
33196  // to disabled the connection) with the original boundary
33197 
33198  } // else if (!connecting_to_an_overlaped_boundary)
33199 
33200  } // if (!connecting_to_an_split_boundary)
33201 #ifdef OOMPH_HAS_MPI
33202  else
33203  {
33204  // If the boundary was split then we need to look for the vertex
33205  // in the sub-polylines
33206 
33207  // Get the sub-polylines vector
33208  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
33209  this->boundary_subpolylines(dst_bnd_id_initial);
33210 
33211  // Get the number of sub-polylines
33212  const unsigned nsub_poly = tmp_vector_subpolylines.size();
33213 #ifdef PARANOID
33214  if (nsub_poly <= 1)
33215  {
33216  std::ostringstream error_message;
33217  error_message
33218  <<"The boundary (" << dst_bnd_id_initial << ") was "
33219  << "marked to be splitted but\n"
33220  << "there are only ("<<nsub_poly<<") polylines to "
33221  << "represent it.\n";
33222  throw OomphLibError(
33223  error_message.str(),
33224  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33225  OOMPH_EXCEPTION_LOCATION);
33226  } // if (nsub_poly <= 1)
33227 #endif
33228  // We need to check if the boundary is marked to be overlaped by
33229  // a shared boundary, if that is the case we need to check for
33230  // each indivual subpolyline, and for those overlaped by a
33231  // shared polyline do nothing, the shared polylines have already
33232  // deal with these connections
33233 
33234  // ... check if the boundary is marked to be overlaped by
33235  // a shared boundary
33236  if (!connecting_to_an_overlaped_boundary)
33237  {
33238  // The boundary is not overlapped by shared boundaries, we can
33239  // work without checking the subpolylines individually (non of
33240  // them are overlapped by a shared boundary)
33241 
33242  // Look for the vertex number to connect on each of the
33243  // subpolyines
33244  for (unsigned isub = 0; isub < nsub_poly; isub++)
33245  {
33246  // Assign the pointer to the sub-polyline
33247  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33248  // Search for the vertex in the current sub-polyline
33249  found_vertex_on_dst_boundary_initial =
33250  this->get_connected_vertex_number_on_destination_polyline(
33251  poly_to_connect_pt,
33252  src_vertex_coordinates_initial,
33253  n_vertex_connection_initial);
33254 
33255  // If we have found the vertex to connect then break the
33256  // loop
33257  if (found_vertex_on_dst_boundary_initial)
33258  {
33259  // But first save the subpoly number (chunk), that will be
33260  // used to perform the connection
33261  sub_poly_to_connect = isub;
33262  break;
33263  } // if (found_vertex_on_dst_boundary_initial)
33264 
33265  } // for (isub < nsub_poly)
33266 
33267  } // if (!connecting_to_an_overlaped_boundary)
33268  else
33269  {
33270  // If connecting to an overlapped boundary then we ignore the
33271  // subpolylines overlapped by shared boundaries and only look
33272  // on the sub-polylines that are not marked as being overlaped
33273  // by shared boundaries
33274 
33275  // Look for the vertex number to connect on each of the
33276  // subpolyines
33277  for (unsigned isub = 0; isub < nsub_poly; isub++)
33278  {
33279  // Only work with those sub-polylines that are not overlaped
33280  // by shared boundaries
33281  if (!this->
33282  boundary_marked_as_shared_boundary(dst_bnd_id_initial, isub))
33283  {
33284  // Assign the pointer to the sub-polyline
33285  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33286 
33287  // Search for the vertex in the current sub-polyline
33288  found_vertex_on_dst_boundary_initial =
33289  this->get_connected_vertex_number_on_destination_polyline(
33290  poly_to_connect_pt,
33291  src_vertex_coordinates_initial,
33292  n_vertex_connection_initial);
33293 
33294  // Was the vertex found?
33295  if (found_vertex_on_dst_boundary_initial)
33296  {
33297  // But first save the subpoly number (chunk), that will
33298  // be used to perform the connection
33299  sub_poly_to_connect = isub;
33300  break;
33301  } // if (found_vertex_on_dst_boundary_initial)
33302 
33303  } // if (not overlaped by shared boundary)
33304 
33305  } // for (isub < nsub_poly)
33306 
33307  } // else if (!connecting_to_an_overlaped_boundary)
33308 
33309  } // else if (!connecting_to_an_split_boundary)
33310 #endif // #ifdef OOMPH_HAS_MPI
33311 
33312  // If not found it may be that the connection information is
33313  // inverted
33314  if (!found_vertex_on_dst_boundary_initial)
33315  {
33316  // Is the mesh distributed?
33317 #ifdef OOMPH_HAS_MPI
33318  if (this->is_mesh_distributed())
33319  {
33320  // If the mesh is distributed and the vertex number was not
33321  // found, that means that the boundary (or vertex) to connect
33322  // in the destination boundary is not in the current
33323  // processor. In that case suspend the connection
33324  polyline_pt->suspend_initial_vertex_connected();
33325  // Add the polyline to the vector of polylines whose
33326  // connection will be resumed at the end of the adaptation
33327  // process
33328  resume_initial_connection_polyline_pt.push_back(polyline_pt);
33329  // The shared boundaries are marked to connect to the initial
33330  // vertex of the polyline (remember that a shared boundary
33331  // stops adding nodes when it finds a node on an original
33332  // boundary) -- The initial vertex is now a base node
33333  }
33334  else
33335 #endif // #ifdef OOMPH_HAS_MPI
33336  {
33337 #ifdef PARANOID
33338  // If not found then there is a problem with the vertices
33339  // Get the associated boundary id of the current polyline
33340  const unsigned bnd_id = polyline_pt->boundary_id();
33341  std::ostringstream error_message;
33342  error_message
33343  << "INITIAL VERTEX CONNECTION\n"
33344  << "It was not possible to find the associated "
33345  << "vertex number on the destination boundary\n"
33346  << "The current boundary (" << bnd_id << ") is marked to have"
33347  << "a connection at the\nINITIAL vertex ("
33348  << src_vertex_coordinates_initial[0] << ","
33349  << src_vertex_coordinates_initial[1] << ")\n"
33350  << "with boundary ("<< dst_bnd_id_initial << ")\n"
33351  << "This is the list of vertices on the destination boundary\n";
33352  // Get the pointer to the associated polyline by using the
33353  // boundary id
33354  TriangleMeshPolyLine *dst_polyline =
33355  this->boundary_polyline_pt(dst_bnd_id_initial);
33356  // The number of vertices on the destination boundary
33357  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
33358  // Loop over the vertices print them
33359  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
33360  {
33361  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
33362  error_message
33363  << "Vertex#(i): ("
33364  << current_vertex[0] << ", " << current_vertex[1] << ")\n";
33365  }
33366  throw OomphLibError(
33367  error_message.str(),
33368  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33369  OOMPH_EXCEPTION_LOCATION);
33370 #endif
33371 
33372  } // else if (this->is_mesh_distributed())
33373 
33374  } // if (!found_vertex_on_dst_boundary_initial)
33375  else
33376  {
33377  // Set the vertex number on the destination boundary
33378  polyline_pt->initial_vertex_connected_n_vertex() =
33379  n_vertex_connection_initial;
33380 
33381  // Set the chunk number on the destination boundary
33382  polyline_pt->initial_vertex_connected_n_chunk() =
33383  sub_poly_to_connect;
33384 
33385  } // else if (!found_vertex_on_dst_boundary_initial)
33386 
33387  } // if (polyline_pt->is_initial_vertex_connected())
33388 
33389  // ------------------------------------------------------------------
33390  // Is the final vertex connected?
33391  if (polyline_pt->is_final_vertex_connected())
33392  {
33393  // The pointer to the boundary to connect
33394  TriangleMeshPolyLine *poly_to_connect_pt = 0;
33395 
33396  // Get the boundary id of the destination/connected boundary
33397  const unsigned dst_bnd_id_final =
33398  polyline_pt->final_vertex_connected_bnd_id();
33399 
33400  // Get the final vertex on the current boundary
33401  const unsigned tmp_n_vertices = polyline_pt->nvertex();
33402  Vector<double> src_vertex_coordinates_final =
33403  polyline_pt->vertex_coordinate(tmp_n_vertices-1);
33404 
33405 
33406 #ifdef PARANOID
33407  // Is the mesh distributed?
33408 #ifdef OOMPH_HAS_MPI
33409  if (this->is_mesh_distributed())
33410  {
33411  // Get the initial shared boundary id
33412  const unsigned init_shd_bnd_id =
33413  this->initial_shared_boundary_id();
33414  // Is the boundary to connect a shared boundary
33415  if (dst_bnd_id_final >= init_shd_bnd_id)
33416  {
33417  // Get the current polyline original boundary id
33418  const unsigned bnd_id = polyline_pt->boundary_id();
33419  std::ostringstream error_message;
33420  error_message
33421  << "FINAL VERTEX CONNECTION\n"
33422  << "The current original boundary is trying to connect to a\n"
33423  << "shared boundary, this is not allowed. In this case the\n"
33424  << "shared boundary should be the one that connects with the\n"
33425  << "original boundary\n"
33426  << "The current boundary (" << bnd_id << ") is marked to have "
33427  << "a connection at the\nFINAL vertex ("
33428  << src_vertex_coordinates_final[0] << ","
33429  << src_vertex_coordinates_final[1] << ")\n"
33430  << "with boundary ("<< dst_bnd_id_final << ")\n"
33431  << "This is the list of vertices on the destination boundary\n";
33432  // Get the pointer to the associated polyline by using the
33433  // boundary id
33434  TriangleMeshPolyLine *dst_polyline =
33435  this->boundary_polyline_pt(dst_bnd_id_final);
33436  // The number of vertices on the destination boundary
33437  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
33438  // Loop over the vertices print them
33439  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
33440  {
33441  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
33442  error_message
33443  << "Vertex#("<<i<<"): ("
33444  << current_vertex[0] << ", " << current_vertex[1] << ")\n";
33445  }
33446  throw OomphLibError(
33447  error_message.str(),
33448  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33449  OOMPH_EXCEPTION_LOCATION);
33450  } // if (dst_bnd_id_initial >= init_shd_bnd_id)
33451 
33452  } // if (this->is_mesh_distributed())
33453 #endif // #ifdef OOMPH_HAS_MPI
33454 
33455 #endif // #ifdef PARANOID
33456 
33457  // Flag to indicate if the vertex was found on the destination
33458  // boundary
33459  bool found_vertex_on_dst_boundary_final = false;
33460 
33461  // Flag that stores the chunk number to connect (only used in
33462  // distributed meshes)
33463  unsigned sub_poly_to_connect = 0;
33464 
33465  // Store the vertex number on the destination boundary
33466  unsigned n_vertex_connection_final = 0;
33467 
33468  // Flags only used in a distributed mesh
33469  // ----------------------------------------
33470  // Flag to indicate we are trying to connect to an split boundary
33471  bool connecting_to_an_split_boundary = false;
33472 
33473  // Flag to indicate we are trying to connecto to an internal
33474  // boundary that is overlaped by a shared boundary)
33475  bool connecting_to_an_overlaped_boundary = false;
33476 
33477 #ifdef OOMPH_HAS_MPI
33478  if (this->is_mesh_distributed())
33479  {
33480  // We can only connect to an original boundary, check if the
33481  // boundary was splitted during the distribution process to
33482  // consider all the chunks (sub-polylines) of the boundary
33483  if (this->boundary_was_splitted(dst_bnd_id_final))
33484  {
33485  connecting_to_an_split_boundary = true;
33486  } // if (this->boundary_was_splitted(dst_bnd_id_final))
33487 
33488  // Check if the destination boundary, or any of its chunks is
33489  // marked to be overlapped by a shared boundary, if that is the
33490  // case we can only connect to the chunks that are not
33491  // overlapped by shared boundaries (the shared boundaries are in
33492  // charge of generating the connections with original boundaries
33493  // and with themselves)
33494  if (connecting_to_an_split_boundary)
33495  {
33496  // Get the number of chucks that represent the destination
33497  // boundary
33498  const unsigned n_sub_poly =
33499  this->nboundary_subpolylines(dst_bnd_id_final);
33500  // Now loop over the chunks of the destination boundary and if
33501  // any of them is marked to be overlaped by a shared boundary
33502  // then set the flag and break the loop
33503  for (unsigned ii =0; ii < n_sub_poly; ii++)
33504  {
33505  if (this->
33506  boundary_marked_as_shared_boundary(dst_bnd_id_final, ii))
33507  {
33508  // Mark the boundary as being overlaped by a shared
33509  // boundary
33510  connecting_to_an_overlaped_boundary = true;
33511  // Break, no need to look for more overlapings
33512  break;
33513  } // if (boundary_marked_as_shared_boundary(...))
33514  } // for (ii < n_sub_poly)
33515  } // if (connecting_to_an_split_boundary)
33516  else
33517  {
33518  // If not connecting to an split boundary then check if the
33519  // whole destination boundary is overlaped by an internal
33520  // boundary
33521  if (this->
33522  boundary_marked_as_shared_boundary(dst_bnd_id_final, 0))
33523  {
33524  // Mark the boundary as being overlaped by a shared boundary
33525  connecting_to_an_overlaped_boundary = true;
33526  } // if (boundary_marked_as_shared_boundary(...))
33527  } // else if (connecting_to_an_split_boundary)
33528 
33529  } // if (this->is_mesh_distributed())
33530 
33531 #endif // #ifdef OOMPH_HAS_MPI
33532 
33533  // If we are connecting neither to an split boundary nor an
33534  // overlaped boundary then get the pointer to the original
33535  // boundary
33536  if (!(connecting_to_an_split_boundary ||
33537  connecting_to_an_overlaped_boundary))
33538  {
33539  // Get the polyline pointer representing the destination
33540  // boundary
33541  poly_to_connect_pt = this->boundary_polyline_pt(dst_bnd_id_final);
33542  } // else if (NOT split, NOT overlaped)
33543 
33544  // Now look for the vertex number on the destination boundary(ies)
33545  // -- in case that the boundary was split ---
33546 
33547  // Do not check for same orientation, that was previously worked
33548  // by interchanging the connections boundaries (if necessary)
33549 
33550  // If the boundary was not split then ...
33551  if (!connecting_to_an_split_boundary)
33552  {
33553  // ... check if the boundary is marked to be overlaped by
33554  // a shared boundary
33555  if (!connecting_to_an_overlaped_boundary)
33556  {
33557  // If that is not the case then we can safely look for the
33558  // vertex number on the destination boundary
33559  found_vertex_on_dst_boundary_final =
33560  this->get_connected_vertex_number_on_destination_polyline(
33561  poly_to_connect_pt,
33562  src_vertex_coordinates_final,
33563  n_vertex_connection_final);
33564 
33565  } // if (!connecting_to_an_overlaped_boundary)
33566  else
33567  {
33568  // If the whole boundary is marked to be overlaped by a shared
33569  // boundary then do nothing, the shared boundaries are already
33570  // in charge of performing the connection (it will be required
33571  // to disabled the connection) with the original boundary
33572 
33573  } // else if (!connecting_to_an_overlaped_boundary)
33574 
33575  } // if (!connecting_to_an_split_boundary)
33576 #ifdef OOMPH_HAS_MPI
33577  else
33578  {
33579  // If the boundary was split then we need to look for the vertex
33580  // in the sub-polylines
33581 
33582  // Get the sub-polylines vector
33583  Vector<TriangleMeshPolyLine*> tmp_vector_subpolylines =
33584  this->boundary_subpolylines(dst_bnd_id_final);
33585 
33586  // Get the number of sub-polylines
33587  const unsigned nsub_poly = tmp_vector_subpolylines.size();
33588 #ifdef PARANOID
33589  if (nsub_poly <= 1)
33590  {
33591  std::ostringstream error_message;
33592  error_message
33593  <<"The boundary (" << dst_bnd_id_final << ") was "
33594  << "marked to be splitted but\n"
33595  << "there are only ("<<nsub_poly<<") polylines to "
33596  << "represent it.\n";
33597  throw OomphLibError(
33598  error_message.str(),
33599  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33600  OOMPH_EXCEPTION_LOCATION);
33601  } // if (nsub_poly <= 1)
33602 #endif
33603  // We need to check if the boundary is marked to be overlaped by
33604  // a shared boundary, if that is the case we need to check for
33605  // each indivual subpolyline, and for those overlaped by a
33606  // shared polyline do nothing, the shared polylines have already
33607  // deal with these connections
33608 
33609  // ... check if the boundary is marked to be overlaped by
33610  // a shared boundary
33611  if (!connecting_to_an_overlaped_boundary)
33612  {
33613  // The boundary is not overlapped by shared boundaries, we can
33614  // work without checking the subpolylines individually (non of
33615  // them are overlapped by a shared boundary)
33616 
33617  // Look for the vertex number to connect on each of the
33618  // subpolyines
33619  for (unsigned isub = 0; isub < nsub_poly; isub++)
33620  {
33621  // Assign the pointer to the sub-polyline
33622  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33623  // Search for the vertex in the current sub-polyline
33624  found_vertex_on_dst_boundary_final =
33625  this->get_connected_vertex_number_on_destination_polyline(
33626  poly_to_connect_pt,
33627  src_vertex_coordinates_final,
33628  n_vertex_connection_final);
33629 
33630  // If we have found the vertex to connect then break the
33631  // loop
33632  if (found_vertex_on_dst_boundary_final)
33633  {
33634  // But first save the subpoly number (chunk), that will be
33635  // used to perform the connection
33636  sub_poly_to_connect = isub;
33637  break;
33638  } // if (found_vertex_on_dst_boundary_initial)
33639 
33640  } // for (isub < nsub_poly)
33641 
33642  } // if (!connecting_to_an_overlaped_boundary)
33643  else
33644  {
33645  // If connecting to an overlapped boundary then we ignore the
33646  // subpolylines overlapped by shared boundaries and only look
33647  // on the sub-polylines that are not marked as being overlaped
33648  // by shared boundaries
33649 
33650  // Look for the vertex number to connect on each of the
33651  // subpolyines
33652  for (unsigned isub = 0; isub < nsub_poly; isub++)
33653  {
33654  // Only work with those sub-polylines that are not overlaped
33655  // by shared boundaries
33656  if (!this->
33657  boundary_marked_as_shared_boundary(dst_bnd_id_final, isub))
33658  {
33659  // Assign the pointer to the sub-polyline
33660  poly_to_connect_pt = tmp_vector_subpolylines[isub];
33661 
33662  // Search for the vertex in the current sub-polyline
33663  found_vertex_on_dst_boundary_final =
33664  this->get_connected_vertex_number_on_destination_polyline(
33665  poly_to_connect_pt,
33666  src_vertex_coordinates_final,
33667  n_vertex_connection_final);
33668 
33669  // Was the vertex found?
33670  if (found_vertex_on_dst_boundary_final)
33671  {
33672  // But first save the subpoly number (chunk), that will
33673  // be used to perform the connection
33674  sub_poly_to_connect = isub;
33675  break;
33676  } // if (found_vertex_on_dst_boundary_final)
33677 
33678  } // if (not overlaped by shared boundary)
33679 
33680  } // for (isub < nsub_poly)
33681 
33682  } // else if (!connecting_to_an_overlaped_boundary)
33683 
33684  } // else if (!connecting_to_an_split_boundary)
33685 #endif // #ifdef OOMPH_HAS_MPI
33686 
33687  // If not found it may be that the connection information is
33688  // inverted
33689  if (!found_vertex_on_dst_boundary_final)
33690  {
33691  // Is the mesh distributed?
33692 #ifdef OOMPH_HAS_MPI
33693  if (this->is_mesh_distributed())
33694  {
33695  // If the mesh is distributed and the vertex number was not
33696  // found, that means that the boundary (or vertex) to connect
33697  // in the destination boundary is not in the current
33698  // processor. In that suspend the connection
33699  polyline_pt->suspend_final_vertex_connected();
33700  // Add the polyline to the vector of polylines whose
33701  // connection will be resumed at the end of the adaptation
33702  // process
33703  resume_final_connection_polyline_pt.push_back(polyline_pt);
33704  // The shared boundaries are marked to connect to the final
33705  // vertex of the polyline (remember that a shared boundary
33706  // stops adding nodes when it finds a node on an original
33707  // boundary) -- The final vertex is now a base node
33708  } // if (this->is_mesh_distributed())
33709  else
33710 #endif // #ifdef OOMPH_HAS_MPI
33711  {
33712 #ifdef PARANOID
33713  // If not found then there is a problem with the vertices
33714  // Get the associated boundary id of the current polyline
33715  const unsigned bnd_id = polyline_pt->boundary_id();
33716  std::ostringstream error_message;
33717  error_message
33718  << "FINAL VERTEX CONNECTION\n"
33719  << "It was not possible to find the associated "
33720  << "vertex number on the destination boundary\n"
33721  << "The current boundary (" << bnd_id << ") is marked to have "
33722  << "a connection at the\nFINAL vertex ("
33723  << src_vertex_coordinates_final[0] << ","
33724  << src_vertex_coordinates_final[1] << ")\n"
33725  << "with boundary ("<< dst_bnd_id_final << ")\n"
33726  << "This is the list of vertices on the destination boundary\n";
33727  // Get the pointer to the associated polyline by using the
33728  // boundary id
33729  TriangleMeshPolyLine *dst_polyline =
33730  this->boundary_polyline_pt(dst_bnd_id_final);
33731  // The number of vertices on the destination boundary
33732  const unsigned n_vertex_dst_boundary = dst_polyline->nvertex();
33733  // Loop over the vertices print them
33734  for (unsigned i = 0; i < n_vertex_dst_boundary; i++)
33735  {
33736  Vector<double> current_vertex = dst_polyline->vertex_coordinate(i);
33737  error_message
33738  << "Vertex#("<<i<<"): ("
33739  << current_vertex[0] << ", " << current_vertex[1] << ")\n";
33740  }
33741  throw OomphLibError(
33742  error_message.str(),
33743  "RefineableTriangleMesh::restore_polyline_connections_helper()",
33744  OOMPH_EXCEPTION_LOCATION);
33745 #endif
33746  } // else if (this->is_mesh_distributed())
33747 
33748  } // if (!found_vertex_on_dst_boundary_final)
33749  else
33750  {
33751  // Set the vertex number on the destination boundary
33752  polyline_pt->final_vertex_connected_n_vertex() =
33753  n_vertex_connection_final;
33754 
33755  // Set the chunk number on the destination boundary
33756  polyline_pt->final_vertex_connected_n_chunk() =
33757  sub_poly_to_connect;
33758 
33759  } // else if (!found_vertex_on_dst_boundary_final)
33760 
33761  } // if (polyline_pt->is_final_vertex_connected())
33762 
33763  }
33764 
33765  //=========================================================================
33766  /// \short Resume the boundary connections that may have been
33767  /// suspended because the destination boundary is no part of the
33768  /// domain. The connections are no permanently suspended because if
33769  /// load balance takes place the destination boundary may be part of
33770  /// the new domain representation therefore the connection would
33771  /// exist
33772  //=========================================================================
33773  template<class ELEMENT>
33775  Vector<TriangleMeshPolyLine*> &resume_initial_connection_polyline_pt,
33776  Vector<TriangleMeshPolyLine*> &resume_final_connection_polyline_pt)
33777  {
33778  // Get the number of polylines that require to resume the connection
33779  // at the initial vertex
33780  const unsigned n_initial_poly =
33781  resume_initial_connection_polyline_pt.size();
33782  // Loop over the polylines that require to resume the connection
33783  // at the initial vertex
33784  for (unsigned p = 0; p < n_initial_poly; p++)
33785  {
33786  // Get the polyline
33787  TriangleMeshPolyLine* tmp_poly_pt =
33788  resume_initial_connection_polyline_pt[p];
33789  // Resume the connection with the initial vertex
33790  tmp_poly_pt->resume_initial_vertex_connected();
33791  } // for (p < n_initial_poly)
33792 
33793  // Get the number of polylines that require to resume the connection
33794  // at the final vertex
33795  const unsigned n_final_poly =
33796  resume_final_connection_polyline_pt.size();
33797  // Loop over the polylines that require to resume the connection at
33798  // the final vertex
33799  for (unsigned p = 0; p < n_final_poly; p++)
33800  {
33801  // Get the polyline
33802  TriangleMeshPolyLine* tmp_poly_pt =
33803  resume_final_connection_polyline_pt[p];
33804  // Resume the connection with the final vertex
33805  tmp_poly_pt->resume_final_vertex_connected();
33806  } // for (p < n_final_poly)
33807 
33808  // Clear the storage
33809  resume_initial_connection_polyline_pt.clear();
33810  resume_final_connection_polyline_pt.clear();
33811 
33812  }
33813 
33814 //=========================================================================
33815 /// \short Gets the associated vertex number according to the vertex
33816 /// coordinates on the destination boundary
33817 //=========================================================================
33818 template<class ELEMENT>
33821  Vector<double> &vertex_coordinates,
33822  const unsigned &dst_bnd_id,
33823  unsigned &vertex_number)
33824  {
33825 
33826  bool found_associated_vertex_number = false;
33827 
33828  // Get the pointer to the associated polyline by using the boundary id
33829  TriangleMeshPolyLine *dst_polyline =
33830  this->boundary_polyline_pt(dst_bnd_id);
33831 
33832  const unsigned n_vertices = dst_polyline->nvertex();
33833 
33834  // Loop over the vertices and return the closest vertex
33835  // to the given vertex coordinates
33836  for (unsigned i = 0; i < n_vertices; i++)
33837  {
33838 
33839  Vector<double> current_vertex =
33840  dst_polyline->vertex_coordinate(i);
33841 
33842  double error =
33843  (vertex_coordinates[0] - current_vertex[0])*
33844  (vertex_coordinates[0] - current_vertex[0])
33845  +
33846  (vertex_coordinates[1] - current_vertex[1])*
33847  (vertex_coordinates[1] - current_vertex[1]);
33848 
33849  error = sqrt(error);
33850 
33851  if(error <
33852  ToleranceForVertexMismatchInPolygons::Tolerable_error)
33853  {
33854  vertex_number = i;
33855  found_associated_vertex_number = true;
33856  break;
33857  }
33858 
33859  }
33860 
33861  return found_associated_vertex_number;
33862 
33863  }
33864 
33865 //=========================================================================
33866 /// \short Helper function that updates the input polygon's PSLG
33867 /// by using the end-points of elements from FaceMesh(es) that are
33868 /// constructed for the boundaries associated with the segments of the
33869 /// polygon. Optional boolean is used to run it as test only (if
33870 /// true is specified as input) in which case polygon isn't actually
33871 /// modified. Returned boolean indicates if polygon was (or would have
33872 /// been -- if called with check_only=false) changed.
33873 //=========================================================================
33874 template<class ELEMENT>
33876 update_polygon_using_face_mesh(TriangleMeshPolygon* polygon_pt,
33877  const bool& check_only)
33878  {
33879 #ifdef PARANOID
33880  // If the mesh is marked as distributed this method can not be
33881  // called since there is no guarantee of creating (distributed)
33882  // meshes that match in the number and position of nodes at their
33883  // shared boundaries. The only exececption is when called with
33884  // check_only=true, since no boundary updating is performed
33885  if (this->is_mesh_distributed() && !check_only)
33886  {
33887  std::stringstream error_message;
33888  error_message
33889  << "The updating of polygons of a distributed mesh can ONLY be\n"
33890  << "performed using the element's area associated to the halo(ed)\n"
33891  << "elements.\n"
33892  << "1) Make sure you have enabled the parallel mesh adaptation\n"
33893  << "option if you are working with a distributed mesh, OR\n"
33894  << "2) Make sure to call the update_..._using_elements_area() methods\n"
33895  << "if the mesh is marked as distributed\n\n";
33896  throw OomphLibError(error_message.str(),
33897  OOMPH_CURRENT_FUNCTION,
33898  OOMPH_EXCEPTION_LOCATION);
33899  } // if (this->is_mesh_distributed())
33900 #endif
33901 
33902  // Boolean that indicates whether an actual update of the polygon
33903  // was performed or not
33904  bool unrefinement_was_performed=false;
33905  bool refinement_was_performed=false;
33906  bool max_length_applied = false;
33907 
33908  //Loop over the number of polylines
33909  const unsigned n_polyline = polygon_pt->npolyline();
33910 
33911  // Get face mesh representation of all polylines, possibly
33912  // with segments re-distributed to maintain an approximately
33913  // even sub-division of the polygon
33914  Vector<Mesh*> face_mesh_pt;
33915  get_face_mesh_representation(polygon_pt,face_mesh_pt);
33916 
33917  // Create vertices for the polylines by using the vertices
33918  // of the FaceElements
33919  Vector<double> vertex_coord(3); // zeta,x,y
33920  Vector<double> bound_left(1);
33921  Vector<double> bound_right(1);
33922 
33923  for(unsigned p=0;p<n_polyline;p++)
33924  {
33925  // Set of coordinates that will be placed on the boundary
33926  // Set entries are ordered on first entry in vector which stores
33927  // the boundary coordinate so the vertices come out in order!
33928  std::set<Vector<double> > vertex_nodes;
33929 
33930  //Get the boundary id
33931  const unsigned bound = polygon_pt->curve_section_pt(p)->boundary_id();
33932 
33933  // Get the chunk number
33934  const unsigned chunk = polygon_pt->curve_section_pt(p)->boundary_chunk();
33935 
33936  // Loop over the face elements (ordered) and add their vertices
33937  unsigned n_face_element = face_mesh_pt[p]->nelement();
33938  for(unsigned e=0;e<n_face_element;++e)
33939  {
33940  FiniteElement* el_pt = face_mesh_pt[p]->finite_element_pt(e);
33941 
33942 #ifdef OOMPH_HAS_MPI
33943  // Only work with non-halo elements if the mesh is distributed
33944  if (this->is_mesh_distributed() && el_pt->is_halo()) {continue;}
33945 #endif
33946 
33947  unsigned n_node = el_pt->nnode();
33948 
33949  //Add the left-hand node to the set:
33950 
33951  // Boundary coordinate
33952  el_pt->node_pt(0)->get_coordinates_on_boundary(bound,bound_left);
33953  vertex_coord[0] = bound_left[0];
33954 
33955  // Actual coordinates
33956  for(unsigned i=0;i<2;i++)
33957  {
33958  vertex_coord[i+1] = el_pt->node_pt(0)->x(i);
33959  }
33960  vertex_nodes.insert(vertex_coord);
33961 
33962  //Add the right-hand nodes to the set:
33963 
33964  //Boundary coordinate
33965  el_pt->node_pt(n_node-1)->
33966  get_coordinates_on_boundary(bound,bound_right);
33967  vertex_coord[0] = bound_right[0];
33968 
33969  // Actual coordinates
33970  for(unsigned i=0;i<2;i++)
33971  {
33972  vertex_coord[i+1] = el_pt->node_pt(n_node-1)->x(i);
33973  }
33974  vertex_nodes.insert(vertex_coord);
33975 
33976  }
33977 
33978  // Now turn into vector for ease of handling...
33979  unsigned n_poly_vertex = vertex_nodes.size();
33980  Vector<Vector<double> > tmp_vector_vertex_node(n_poly_vertex);
33981  unsigned count=0;
33982  for(std::set<Vector<double> >::iterator it = vertex_nodes.begin();
33983  it!=vertex_nodes.end();++it)
33984  {
33985  tmp_vector_vertex_node[count].resize(3);
33986  tmp_vector_vertex_node[count][0] = (*it)[0];
33987  tmp_vector_vertex_node[count][1] = (*it)[1];
33988  tmp_vector_vertex_node[count][2] = (*it)[2];
33989  ++count;
33990  }
33991 
33992  // Size of the vector
33993  unsigned n_vertex=tmp_vector_vertex_node.size();
33994 
33995  // Tolerance below which the middle point can be deleted
33996  // (ratio of deflection to element length)
33997  double unrefinement_tolerance=
33998  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
33999 
34000  //------------------------------------------------------
34001  // Unrefinement
34002  //------------------------------------------------------
34003  if (unrefinement_tolerance>0.0 && n_vertex>=3)
34004  {
34005  unrefinement_was_performed =
34006  unrefine_boundary(bound, chunk, tmp_vector_vertex_node,
34007  unrefinement_tolerance, check_only);
34008 
34009  // In this case the "unrefinement_was_performed" variable
34010  // tell us if the update had been performed when calling
34011  // with check_oly=false
34012  if (check_only && unrefinement_was_performed)
34013  {
34014  // Cleanup (but only the elements -- the nodes still exist in
34015  // the bulk mesh!
34016  for(unsigned p=0;p<n_polyline;p++)
34017  {
34018  face_mesh_pt[p]->flush_node_storage();
34019  delete face_mesh_pt[p];
34020  }
34021  return true;
34022  }
34023 
34024  } // end of unrefinement
34025 
34026  // Do not perform refinement if there are no more than two vertices
34027  // New size of the vector
34028  n_vertex=tmp_vector_vertex_node.size();
34029 
34030  //------------------------------------------------
34031  // Refinement
34032  //------------------------------------------------
34033  double refinement_tolerance=
34034  polygon_pt->polyline_pt(p)->refinement_tolerance();
34035  if (refinement_tolerance>0.0 && n_vertex >= 2)
34036  {
34037  refinement_was_performed =
34038  refine_boundary(face_mesh_pt[p], tmp_vector_vertex_node,
34039  refinement_tolerance, check_only);
34040 
34041  // In this case the "refinement_was_performed" variable
34042  // tell us if the update had been performed when calling
34043  // with check_only=false
34044  if (check_only && refinement_was_performed)
34045  {
34046  // Cleanup (but only the elements -- the nodes still exist in
34047  // the bulk mesh!
34048  for(unsigned p=0;p<n_polyline;p++)
34049  {
34050  face_mesh_pt[p]->flush_node_storage();
34051  delete face_mesh_pt[p];
34052  }
34053  return true;
34054  }
34055 
34056  } // end refinement
34057 
34058  // Do not perform maximum length constraint if there are no more than
34059  // two vertices
34060  // New size of the vector
34061  n_vertex=tmp_vector_vertex_node.size();
34062 
34063  //------------------------------------------------
34064  // Maximum length constrait
34065  //-----------------------------------------------
34066  double maximum_length = polygon_pt->polyline_pt(p)->maximum_length();
34067  if (maximum_length > 0.0 && n_vertex >= 2)
34068  {
34069  max_length_applied =
34070  apply_max_length_constraint(face_mesh_pt[p],
34071  tmp_vector_vertex_node,
34072  maximum_length);
34073 
34074  // In this case the max length criteria was applied, check if
34075  // check_only=false
34076  if (check_only && max_length_applied)
34077  {
34078  // Cleanup (but only the elements -- the nodes still exist in
34079  // the bulk mesh!
34080  for(unsigned p=0;p<n_polyline;p++)
34081  {
34082  face_mesh_pt[p]->flush_node_storage();
34083  delete face_mesh_pt[p];
34084  }
34085  return true;
34086  }
34087 
34088  }
34089 
34090  // For further processing the three-dimensional vector
34091  // has to be reduced to a two-dimensional vector
34092  n_vertex=tmp_vector_vertex_node.size();
34093  Vector<Vector<double> > vector_vertex_node(n_vertex);
34094 
34095  for(unsigned i=0;i<n_vertex;i++)
34096  {
34097  vector_vertex_node[i].resize(2);
34098  vector_vertex_node[i][0]=tmp_vector_vertex_node[i][1];
34099  vector_vertex_node[i][1]=tmp_vector_vertex_node[i][2];
34100  }
34101 
34102 #ifdef OOMPH_HAS_MPI
34103  // Only perform this checking if the mesh is not distributed. When
34104  // the mesh is distributed the polylines continuity is addressed in
34105  // the sort_polylines_helper() method
34106  if (!this->is_mesh_distributed())
34107 #endif
34108  {
34109  if ( (p > 0) && !check_only )
34110  {
34111  //Final end point of previous line
34112  Vector<double> final_vertex_of_previous_segment;
34113  unsigned n_prev_vertex =
34114  polygon_pt->curve_section_pt(p-1)->nvertex();
34115  final_vertex_of_previous_segment =
34116  polygon_pt->polyline_pt(p-1)->
34117  vertex_coordinate(n_prev_vertex-1);
34118 
34119  unsigned prev_seg_boundary_id =
34120  polygon_pt->curve_section_pt(p-1)->boundary_id();
34121 
34122  //Find the error between the final vertex of the previous
34123  //line and the first vertex of the current line
34124  double error = 0.0;
34125  for(unsigned i=0;i<2;i++)
34126  {
34127  const double dist =
34128  final_vertex_of_previous_segment[i] -
34129  (*vector_vertex_node.begin())[i];
34130  error += dist*dist;
34131  }
34132  error = sqrt(error);
34133 
34134  //If the error is bigger than the tolerance then
34135  //we probably need to reverse, but better check
34136  if(error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
34137  {
34138  //Find the error between the final vertex of the previous
34139  //line and the last vertex of the current line
34140  double rev_error = 0.0;
34141  for(unsigned i=0;i<2;i++)
34142  {
34143  const double dist =
34144  final_vertex_of_previous_segment[i] -
34145  (*--vector_vertex_node.end())[i];
34146  rev_error += dist*dist;
34147  }
34148  rev_error = sqrt(rev_error);
34149 
34150  if(rev_error >
34151  ToleranceForVertexMismatchInPolygons::Tolerable_error)
34152  {
34153  // It could be possible that the first segment be reversed and we
34154  // did not notice it because this check does not apply for the
34155  // first segment. We can verify if the first segment is reversed
34156  // by using the vertex number 1
34157  if (p == 1)
34158  {
34159 
34160  //Initial end point of previous line
34161  Vector<double> initial_vertex_of_previous_segment;
34162 
34163  initial_vertex_of_previous_segment =
34164  polygon_pt->polyline_pt(p-1)->
34165  vertex_coordinate(0);
34166 
34167  unsigned prev_seg_boundary_id =
34168  polygon_pt->curve_section_pt(p-1)->boundary_id();
34169 
34170  //Find the error between the initial vertex of the previous
34171  //line and the first vertex of the current line
34172  double error = 0.0;
34173  for(unsigned i=0;i<2;i++)
34174  {
34175  const double dist =
34176  initial_vertex_of_previous_segment[i] -
34177  (*vector_vertex_node.begin())[i];
34178  error += dist*dist;
34179  }
34180  error = sqrt(error); // Reversed only the previous one
34181 
34182  //If the error is bigger than the tolerance then
34183  //we probably need to reverse, but better check
34184  if(error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
34185  {
34186  //Find the error between the final vertex of the previous
34187  //line and the last vertex of the current line
34188  double rev_error = 0.0;
34189  for(unsigned i=0;i<2;i++)
34190  {
34191  const double dist =
34192  initial_vertex_of_previous_segment[i] -
34193  (*--vector_vertex_node.end())[i];
34194  rev_error += dist*dist;
34195  }
34196  rev_error = sqrt(rev_error); // Reversed both the current one and
34197  // the previous one
34198 
34199  if (rev_error >
34200  ToleranceForVertexMismatchInPolygons::Tolerable_error)
34201  {
34202  std::ostringstream error_stream;
34203  error_stream
34204  <<"The distance between the first node of the current\n"
34205  <<"line segment (boundary " << bound << ") and either end of "
34206  << "the previous line segment\n"
34207  << "(boundary " << prev_seg_boundary_id << ") is bigger than "
34208  << "the desired tolerance " <<
34209  ToleranceForVertexMismatchInPolygons::Tolerable_error << ".\n"
34210  << "This suggests that the polylines defining the polygonal\n"
34211  << "representation are not properly ordered.\n"
34212  << "Fail on last vertex of polyline: ("
34213  << prev_seg_boundary_id<< ") and\nfirst vertex of polyline ("
34214  << bound << ").\nThis should have failed when first trying to "
34215  << "construct the\npolygon.\n";
34216  throw OomphLibError(error_stream.str(),
34217  OOMPH_CURRENT_FUNCTION,
34218  OOMPH_EXCEPTION_LOCATION);
34219 
34220  }
34221  else
34222  {
34223  // Reverse both
34224  // Reverse the current vector to line up with the previous one
34225  std::reverse(vector_vertex_node.begin(),
34226  vector_vertex_node.end());
34227 
34228  polygon_pt->polyline_pt(p-1)->reverse();
34229  }
34230  }
34231  else
34232  {
34233  // Reverse the previous one
34234  polygon_pt->polyline_pt(p-1)->reverse();
34235  }
34236 
34237  } // if p == 1
34238  else
34239  {
34240  std::ostringstream error_stream;
34241  error_stream
34242  <<"The distance between the first node of the current\n"
34243  <<"line segment (boundary " << bound << ") and either end of "
34244  << "the previous line segment\n"
34245  << "(boundary " << prev_seg_boundary_id << ") is bigger than the "
34246  << "desired tolerance " <<
34247  ToleranceForVertexMismatchInPolygons::Tolerable_error << ".\n"
34248  <<"This suggests that the polylines defining the polygonal\n"
34249  <<"representation are not properly ordered.\n"
34250  << "Fail on last vertex of polyline: (" << prev_seg_boundary_id
34251  << ") and\nfirst vertex of polyline (" << bound << ").\n"
34252  << "This should have failed when first trying to construct the\n"
34253  << "polygon.\n";
34254  throw OomphLibError(error_stream.str(),
34255  OOMPH_CURRENT_FUNCTION,
34256  OOMPH_EXCEPTION_LOCATION);
34257  }
34258  }
34259  else
34260  {
34261  //Reverse the current vector to line up with the previous one
34262  std::reverse(vector_vertex_node.begin(),vector_vertex_node.end());
34263  }
34264 
34265  } // first error
34266  } // p > 0
34267  } // is mesh not distributed?
34268 
34269  if(!check_only)
34270  {
34271  // Now update the polyline according to the new vertices
34272  // The new one representation
34273  TriangleMeshPolyLine *tmp_polyline_pt =
34274  new TriangleMeshPolyLine(vector_vertex_node,bound);
34275 
34276  // Create a temporal "curve section" version of the recently created
34277  // polyline
34278  TriangleMeshCurveSection *tmp_curve_section_pt = tmp_polyline_pt;
34279 
34280  // Establish refinement and unrefinement tolerance
34281  tmp_polyline_pt->set_unrefinement_tolerance(
34282  unrefinement_tolerance);
34283  tmp_polyline_pt->set_refinement_tolerance(
34284  refinement_tolerance);
34285 
34286  // Establish the maximum length constraint
34287  tmp_polyline_pt->set_maximum_length(maximum_length);
34288 
34289  // We pass the connection information from the old polyline to
34290  // the new one
34291  this->copy_connection_information(polygon_pt->polyline_pt(p),
34292  tmp_curve_section_pt);
34293 
34294  //Now update the polyline according to the new vertices but
34295  //first check if the object is allowed to delete the representation
34296  //or if it should be done by other object
34297  bool delete_it_on_destructor = false;
34298 
34299  std::set<TriangleMeshCurveSection*>::iterator it =
34300  this->Free_curve_section_pt.find(polygon_pt->curve_section_pt(p));
34301 
34302  if (it!=this->Free_curve_section_pt.end())
34303  {
34304  this->Free_curve_section_pt.erase(it);
34305  delete polygon_pt->curve_section_pt(p);
34306  delete_it_on_destructor = true;
34307  }
34308 
34309  // ------------------------------------------------------------
34310  // Copying the new representation
34311  polygon_pt->curve_section_pt(p) = tmp_polyline_pt;
34312 
34313  // Update the Boundary - Polyline map
34314  this->Boundary_curve_section_pt[bound] = polygon_pt->curve_section_pt(p);
34315 
34316  if (delete_it_on_destructor)
34317  {
34318  this->Free_curve_section_pt.insert(polygon_pt->curve_section_pt(p));
34319  }
34320 
34321  } // if(!check_only)
34322 
34323  } // for (p < n_polyline)
34324 
34325  // Cleanup (but only the elements -- the nodes still exist in
34326  // the bulk mesh!
34327  for(unsigned p=0;p<n_polyline;p++)
34328  {
34329  face_mesh_pt[p]->flush_node_storage();
34330  delete face_mesh_pt[p];
34331  }
34332 
34333  if(check_only)
34334  {
34335  // if we end up all the way down here, no update of the internal boundaries
34336  // is necessary (in case we only check)
34337  return false;
34338  }
34339  else
34340  {
34341  // if we not only check, but actually perform the update and end up
34342  // all the way down here then we indicate whether an update was performed
34343  // or not
34344  return (unrefinement_was_performed ||
34345  refinement_was_performed ||
34346  max_length_applied);
34347  }
34348 
34349  }
34350 
34351 //=========================================================================
34352 /// \short Helper function that updates the input open curve by using
34353 /// end-points of elements from FaceMesh(es) that are constructed for the
34354 /// boundaries associated with the polylines. Optional boolean is used to
34355 /// run it as test only (if true is specified as input) in which case the
34356 /// polylines are not actually modified. Returned boolean indicates if
34357 /// polylines were (or would have been -- if called with check_only=false)
34358 /// changed.
34359 //=========================================================================
34360 template<class ELEMENT>
34362 update_open_curve_using_face_mesh(TriangleMeshOpenCurve* open_polyline_pt,
34363  const bool& check_only)
34364  {
34365 #ifdef PARANOID
34366  // If the mesh is marked as distributed this method can not be
34367  // called since there is no guarantee of creating (distributed)
34368  // meshes that match in the number and position of nodes at their
34369  // shared boundaries. The only exececption is when called with
34370  // check_only=true, since no boundary updating is performed
34371  if (this->is_mesh_distributed() && !check_only)
34372  {
34373  std::stringstream error_message;
34374  error_message
34375  << "The updating of open curves of a distributed mesh can ONLY be\n"
34376  << "performed using the element's area associated to the halo(ed)\n"
34377  << "elements.\n"
34378  << "1) Make sure you have enabled the parallel mesh adaptation\n"
34379  << "option if you are working with a distributed mesh, OR\n"
34380  << "2) Make sure to call the update_..._using_elements_area() methods\n"
34381  << "if the mesh is marked as distributed\n\n";
34382  throw OomphLibError(error_message.str(),
34383  OOMPH_CURRENT_FUNCTION,
34384  OOMPH_EXCEPTION_LOCATION);
34385  } // if (this->is_mesh_distributed())
34386 #endif
34387 
34388  // Boolean that indicates whether an actual update of the polylines
34389  // were performed or not
34390  bool unrefinement_was_performed=false;
34391  bool refinement_was_performed=false;
34392  bool max_length_applied = false;
34393 
34394  //Loop over the number of polylines
34395  const unsigned n_polyline = open_polyline_pt->ncurve_section();
34396 
34397  // Get face mesh representation of all polylines, possibly
34398  // with segments re-distributed to maintain an approximately
34399  // even sub-division of the polygon
34400  Vector<Mesh*> face_mesh_pt;
34401  get_face_mesh_representation(open_polyline_pt, face_mesh_pt);
34402 
34403  // Create vertices for the polylines by using the vertices
34404  // of the FaceElements
34405  Vector<double> vertex_coord(3); // zeta,x,y
34406  Vector<double> bound_left(1);
34407  Vector<double> bound_right(1);
34408 
34409  for(unsigned p=0;p<n_polyline;p++)
34410  {
34411  // Set of coordinates that will be placed on the boundary
34412  // Set entries are ordered on first entry in vector which stores
34413  // the boundary coordinate so the vertices come out in order!
34414  std::set<Vector<double> > vertex_nodes;
34415 
34416  //Get the boundary id
34417  const unsigned bound =
34418  open_polyline_pt->curve_section_pt(p)->boundary_id();
34419 
34420  // Get the chunk number
34421  const unsigned chunk =
34422  open_polyline_pt->curve_section_pt(p)->boundary_chunk();
34423 
34424  // Loop over the face elements (ordered) and add their vertices
34425  unsigned n_face_element = face_mesh_pt[p]->nelement();
34426 
34427  //n_count = 0;
34428  for(unsigned e=0;e<n_face_element;++e)
34429  {
34430  FiniteElement* el_pt = face_mesh_pt[p]->finite_element_pt(e);
34431  unsigned n_node = el_pt->nnode();
34432 
34433  //Add the left-hand node to the set:
34434 
34435  // Boundary coordinate
34436  el_pt->node_pt(0)->get_coordinates_on_boundary(bound,bound_left);
34437  vertex_coord[0] = bound_left[0];
34438 
34439  // Actual coordinates
34440  for(unsigned i=0;i<2;i++)
34441  {
34442  vertex_coord[i+1] = el_pt->node_pt(0)->x(i);
34443  }
34444  vertex_nodes.insert(vertex_coord);
34445 
34446  //Add the right-hand nodes to the set:
34447 
34448  //Boundary coordinate
34449  el_pt->node_pt(n_node-1)->get_coordinates_on_boundary(bound,bound_right);
34450  vertex_coord[0] = bound_right[0];
34451 
34452  // Actual coordinates
34453  for(unsigned i=0;i<2;i++)
34454  {
34455  vertex_coord[i+1] = el_pt->node_pt(n_node-1)->x(i);
34456  }
34457  vertex_nodes.insert(vertex_coord);
34458 
34459  }
34460 
34461  // Now turn into vector for ease of handling...
34462  unsigned n_poly_vertex = vertex_nodes.size();
34463  Vector<Vector<double> > tmp_vector_vertex_node(n_poly_vertex);
34464  unsigned count=0;
34465  for(std::set<Vector<double> >::iterator it = vertex_nodes.begin();
34466  it!=vertex_nodes.end();++it)
34467  {
34468  tmp_vector_vertex_node[count].resize(3);
34469  tmp_vector_vertex_node[count][0] = (*it)[0];
34470  tmp_vector_vertex_node[count][1] = (*it)[1];
34471  tmp_vector_vertex_node[count][2] = (*it)[2];
34472  ++count;
34473  }
34474 
34475  // Size of the vector
34476  unsigned n_vertex=tmp_vector_vertex_node.size();
34477 
34478  // Tolerance below which the middle point can be deleted
34479  // (ratio of deflection to element length)
34480  double unrefinement_tolerance=
34481  open_polyline_pt->polyline_pt(p)->unrefinement_tolerance();
34482 
34483  //------------------------------------------------------
34484  // Unrefinement
34485  //------------------------------------------------------
34486  if (unrefinement_tolerance>0.0 && n_vertex>=3)
34487  {
34488  unrefinement_was_performed =
34489  unrefine_boundary(bound, chunk, tmp_vector_vertex_node,
34490  unrefinement_tolerance, check_only);
34491 
34492  // In this case the unrefinement_was_performed variable actually
34493  // tell us if the update had been performed when calling
34494  // with check_only=false
34495  if (check_only && unrefinement_was_performed)
34496  {
34497  // Cleanup (but only the elements -- the nodes still exist in
34498  // the bulk mesh!
34499  for(unsigned p=0;p<n_polyline;p++)
34500  {
34501  face_mesh_pt[p]->flush_node_storage();
34502  delete face_mesh_pt[p];
34503  }
34504  return true;
34505  }
34506 
34507  } // end of unrefinement
34508 
34509  // Do not perform refinement if there are no more than two vertices
34510  // (open curve version)
34511  // New size of the vector
34512  n_vertex=tmp_vector_vertex_node.size();
34513 
34514  //------------------------------------------------
34515  /// Refinement
34516  //------------------------------------------------
34517  double refinement_tolerance=
34518  open_polyline_pt->polyline_pt(p)->refinement_tolerance();
34519  if (refinement_tolerance>0.0 && n_vertex >= 2)
34520  {
34521  refinement_was_performed =
34522  refine_boundary(face_mesh_pt[p], tmp_vector_vertex_node,
34523  refinement_tolerance, check_only);
34524 
34525  // In this case the unrefinement_was_performed variable actually
34526  // tell us if the update had been performed when calling
34527  // with check_only=false
34528  if (check_only && refinement_was_performed)
34529  {
34530  // Cleanup (but only the elements -- the nodes still exist in
34531  // the bulk mesh!
34532  for(unsigned p=0;p<n_polyline;p++)
34533  {
34534  face_mesh_pt[p]->flush_node_storage();
34535  delete face_mesh_pt[p];
34536  }
34537  return true;
34538  }
34539 
34540  } // end refinement
34541 
34542  // Do not perform maximum length constraint if there are no more than
34543  // two vertices
34544  // New size of the vector
34545  n_vertex=tmp_vector_vertex_node.size();
34546 
34547  //------------------------------------------------
34548  // Maximum length constraint
34549  //-----------------------------------------------
34550  double maximum_length = open_polyline_pt->polyline_pt(p)->maximum_length();
34551  if (maximum_length > 0.0 && n_vertex >= 2)
34552  {
34553  bool max_length_applied = false;
34554  max_length_applied =
34555  apply_max_length_constraint(face_mesh_pt[p],
34556  tmp_vector_vertex_node,
34557  maximum_length);
34558 
34559  // In this case the max length criteria was applied, check if
34560  // check_only=false
34561  if (check_only && max_length_applied)
34562  {
34563  // Cleanup (but only the elements -- the nodes still exist in
34564  // the bulk mesh!
34565  for(unsigned p=0;p<n_polyline;p++)
34566  {
34567  face_mesh_pt[p]->flush_node_storage();
34568  delete face_mesh_pt[p];
34569  }
34570  return true;
34571  }
34572 
34573  }
34574 
34575  // For further processing the three-dimensional vector
34576  // has to be reduced to a two-dimensional vector
34577  n_vertex=tmp_vector_vertex_node.size();
34578  Vector<Vector<double> > vector_vertex_node(n_vertex);
34579 
34580  for(unsigned i=0;i<n_vertex;i++)
34581  {
34582  vector_vertex_node[i].resize(2);
34583  vector_vertex_node[i][0]=tmp_vector_vertex_node[i][1];
34584  vector_vertex_node[i][1]=tmp_vector_vertex_node[i][2];
34585  }
34586 
34587 #ifdef OOMPH_HAS_MPI
34588  // Only perform this checking if the mesh is not distributed. When
34589  // the mesh is distributed the polylines continuity is addressed
34590  // in the sort_polylines_helper() method
34591  if (!this->is_mesh_distributed())
34592 #endif
34593  {
34594  //Check whether the segments are continguous (first vertex of this
34595  //segment is equal to last vertex of previous segment).
34596  //If not, we should reverse the order of the current segment.
34597  //This check only applies for segments other than the first.
34598  //We only bother with this check, if we actually perform an update
34599  //of the polyline, i.e. if it's not only a check
34600  if( (p > 0) && !check_only )
34601  {
34602  //Final end point of previous line
34603  Vector<double> final_vertex_of_previous_segment;
34604  open_polyline_pt->polyline_pt(p-1)->
34605  final_vertex_coordinate(final_vertex_of_previous_segment);
34606 
34607  unsigned prev_seg_boundary_id =
34608  open_polyline_pt->curve_section_pt(p-1)->boundary_id();
34609 
34610  //Find the error between the final vertex of the previous
34611  //line and the first vertex of the current line
34612  double error = 0.0;
34613  for(unsigned i=0;i<2;i++)
34614  {
34615  const double dist =
34616  final_vertex_of_previous_segment[i] -
34617  (*vector_vertex_node.begin())[i];
34618  error += dist*dist;
34619  }
34620  error = sqrt(error);
34621 
34622  //If the error is bigger than the tolerance then
34623  //we probably need to reverse, but better check
34624  if(error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
34625  {
34626  //Find the error between the final vertex of the previous
34627  //line and the first vertex of the current line
34628  error = 0.0;
34629  for(unsigned i=0;i<2;i++)
34630  {
34631  const double dist =
34632  final_vertex_of_previous_segment[i] -
34633  (*--vector_vertex_node.end())[i];
34634  error += dist*dist;
34635  }
34636  error = sqrt(error);
34637 
34638  if (error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
34639  {
34640  // It could be possible that the first segment be reversed
34641  // and we did not notice it because this check does not
34642  // apply for the first segment. We can verify if the first
34643  // segment is reversed by using the vertex number 1
34644  if (p == 1)
34645  {
34646  // If no found it is possible that the previous polyline
34647  // be reversed Check for that case Initial point of
34648  // previous line
34649  Vector<double> initial_vertex_of_previous_segment;
34650  open_polyline_pt->polyline_pt(p-1)->
34651  initial_vertex_coordinate(initial_vertex_of_previous_segment);
34652 
34653  //Find the error between the initial vertex of the previous
34654  //line and the first vertex of the current line
34655  error = 0.0;
34656  for(unsigned i=0;i<2;i++)
34657  {
34658  const double dist =
34659  initial_vertex_of_previous_segment[i] -
34660  (*vector_vertex_node.begin())[i];
34661  error += dist*dist;
34662  }
34663  error = sqrt(error);
34664 
34665  //If the error is bigger than the tolerance then
34666  //we probably need to reverse, but better check
34667  if(error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
34668  {
34669  //Find the error between the final vertex of the previous
34670  //line and the first vertex of the current line
34671  error = 0.0;
34672  for(unsigned i=0;i<2;i++)
34673  {
34674  const double dist =
34675  initial_vertex_of_previous_segment[i] -
34676  (*--vector_vertex_node.end())[i];
34677  error += dist*dist;
34678  }
34679  error = sqrt(error);
34680 
34681  if(error >
34682  ToleranceForVertexMismatchInPolygons::Tolerable_error)
34683  {
34684  std::ostringstream error_stream;
34685  error_stream
34686  <<"The distance between the first node of the current\n"
34687  <<"line segment (boundary " << bound
34688  <<") and either end of the previous line segment\n"
34689  <<"(boundary " << prev_seg_boundary_id << ") is bigger than "
34690  <<"the desired tolerance " <<
34691  ToleranceForVertexMismatchInPolygons::Tolerable_error<<".\n"
34692  <<"This suggests that the polylines defining the open "
34693  << "curve\n"
34694  <<"representation are not properly ordered.\n"
34695  <<"Fail on last vertex of polyline: ("
34696  << prev_seg_boundary_id
34697  <<") and\nfirst vertex of polyline (" << bound << ").\n"
34698  <<"This should have failed when first trying to construct\n"
34699  <<"the open curve.\n";
34700  throw OomphLibError(error_stream.str(),
34701  OOMPH_CURRENT_FUNCTION,
34702  OOMPH_EXCEPTION_LOCATION);
34703  }
34704  else // We have to reverse both
34705  {
34706  // First reverse the previous polyline
34707  open_polyline_pt->polyline_pt(p-1)->reverse();
34708  // Then reverse the current polyline
34709  std::reverse(vector_vertex_node.begin(),
34710  vector_vertex_node.end());
34711  }
34712  }
34713  else
34714  {
34715  // Reverse the previous polyline only
34716  open_polyline_pt->polyline_pt(p-1)->reverse();
34717  }
34718  } // if (p == 1)
34719  else
34720  {
34721  std::ostringstream error_stream;
34722  error_stream
34723  << "The distance between the first node of the current\n"
34724  << "line segment (boundary " << bound << ") and either end of "
34725  << "the previous line segment\n"
34726  << "(boundary "<<prev_seg_boundary_id<<") is bigger than the "
34727  << "desired tolerance " <<
34728  ToleranceForVertexMismatchInPolygons::Tolerable_error << ".\n"
34729  <<"This suggests that the polylines defining the polygonal\n"
34730  <<"representation are not properly ordered.\n"
34731  << "Fail on last vertex of polyline: ("<<prev_seg_boundary_id
34732  << ") and\nfirst vertex of polyline ("<<bound<<").\n"
34733  << "This should have failed when first trying to construct the\n"
34734  << "polygon.\n";
34735  throw OomphLibError(error_stream.str(),
34736  OOMPH_CURRENT_FUNCTION,
34737  OOMPH_EXCEPTION_LOCATION);
34738  }
34739  }
34740  else
34741  {
34742  //Reverse the current vector to line up with the previous one
34743  std::reverse(vector_vertex_node.begin(),vector_vertex_node.end());
34744  }
34745 
34746  }
34747 
34748  } // if p > 0
34749 
34750  } // is mesh not distributed?
34751 
34752  if(!check_only)
34753  {
34754  // Now update the polyline according to the new vertices The new
34755  // one representation
34756  TriangleMeshPolyLine *tmp_polyline =
34757  new TriangleMeshPolyLine(vector_vertex_node, bound);
34758 
34759  // Create a temporal "curve section" version of the recently
34760  // created polyline
34761  TriangleMeshCurveSection *tmp_curve_section = tmp_polyline;
34762 
34763  // Copy the unrefinement and refinement information
34764  tmp_polyline->set_unrefinement_tolerance(
34765  unrefinement_tolerance);
34766  tmp_polyline->set_refinement_tolerance(
34767  refinement_tolerance);
34768 
34769  // Establish the maximum length constraint
34770  tmp_polyline->set_maximum_length(maximum_length);
34771 
34772  // Pass the connection information from the old polyline to the
34773  // new one
34774  this->copy_connection_information(open_polyline_pt->polyline_pt(p),
34775  tmp_curve_section);
34776 
34777  std::set<TriangleMeshCurveSection*>::iterator it =
34778  this->Free_curve_section_pt.find(open_polyline_pt->curve_section_pt(p));
34779 
34780  bool delete_it_on_destructor = false;
34781 
34782  if (it!=this->Free_curve_section_pt.end())
34783  {
34784  // Free previous representation only if you created
34785  this->Free_curve_section_pt.erase(it);
34786  delete open_polyline_pt->curve_section_pt(p);
34787  delete_it_on_destructor = true;
34788  }
34789 
34790  // *****************************************************************
34791  // Copying the new representation
34792  open_polyline_pt->curve_section_pt(p) = tmp_polyline;
34793 
34794  // Update the Boundary <--> PolyLine map
34795  this->Boundary_curve_section_pt[bound] =
34796  open_polyline_pt->curve_section_pt(p);
34797 
34798  if (delete_it_on_destructor)
34799  {
34800  this->Free_curve_section_pt.insert(
34801  open_polyline_pt->curve_section_pt(p));
34802  }
34803 
34804  } // if(!check_only)
34805 
34806  } // n_polylines
34807 
34808  // Cleanup (but only the elements -- the nodes still exist in
34809  // the bulk mesh!
34810  for(unsigned p=0;p<n_polyline;p++)
34811  {
34812  face_mesh_pt[p]->flush_node_storage();
34813  delete face_mesh_pt[p];
34814  }
34815 
34816  if(check_only)
34817  {
34818  // if we end up all the way down here, no update of the internal
34819  // boundaries is necessary (in case we only check)
34820  return false;
34821  }
34822  else
34823  {
34824  // if we not only check, but actually perform the update and end
34825  // up all the way down here then we indicate whether an update was
34826  // performed or not
34827  return (unrefinement_was_performed ||
34828  refinement_was_performed ||
34829  max_length_applied);
34830  }
34831 
34832  }
34833 
34834 //=========================================================================
34835 /// \short Helper function that performs the unrefinement process
34836 /// on the specified boundary by using the provided vertices
34837 /// representation. Optional boolean is used to run it as test only (if
34838 /// true is specified as input) in which case vertex coordinates aren't
34839 /// actually modified. Returned boolean indicates if polyline was (or
34840 /// would have been -- if called with check_only=false) changed.
34841 //=========================================================================
34842 template<class ELEMENT>
34844 unrefine_boundary(const unsigned &b,
34845  const unsigned &c,
34846  Vector<Vector<double> > &vector_bnd_vertices,
34847  double &unrefinement_tolerance,
34848  const bool &check_only)
34849  {
34850  // Store the vertices not allowed for deletion
34851  std::set<Vector<double> > no_delete_vertex;
34852 
34853  // Does the boundary receives connections?
34854  const bool boundary_receive_connections =
34855  this->boundary_connections(b, c, no_delete_vertex);
34856 
34857  // Boolean that indicates whether an actual update of the vertex
34858  // coordinates was performed or not
34859  bool unrefinement_was_performed=false;
34860 
34861  unsigned n_vertex = vector_bnd_vertices.size();
34862 
34863  // Initialise counter that indicates at which vertex we're currently
34864  // considering for deletion
34865  unsigned counter=1;
34866 
34867  // Loop over the nodes; start with the second one and increment by two
34868  // this way a "pack" of three nodes will be considered for calculation:
34869  // the middle-node (which is to be deleted or not) and the adjacent
34870  // nodes
34871  for(unsigned i=1;i<=n_vertex-2;i+=2)
34872  {
34873  // Maths from http://www.cgafaq.info/wiki/Circle_Through_Three_Points
34874  double a_x=vector_bnd_vertices[i-1][1];
34875  double a_y=vector_bnd_vertices[i-1][2];
34876  double b_x=vector_bnd_vertices[i][1];
34877  double b_y=vector_bnd_vertices[i][2];
34878  double c_x=vector_bnd_vertices[i+1][1];
34879  double c_y=vector_bnd_vertices[i+1][2];
34880 
34881  double a=b_x-a_x;
34882  double b=b_y-a_y;
34883  double c=c_x-a_x;
34884  double d=c_y-a_y;
34885 
34886  double e=a*(a_x+b_x)+b*(a_y+b_y);
34887  double f=c*(a_x+c_x)+d*(a_y+c_y);
34888 
34889  double g=2.0*(a*(c_y-b_y)-b*(c_x-b_x));
34890 
34891  bool do_it=false;
34892  if (std::fabs(g)<1.0e-14)
34893  {
34894  do_it=true;
34895  if(check_only) {return true;}
34896  }
34897  else
34898  {
34899  double p_x=(d*e-b*f)/g;
34900  double p_y=(a*f-c*e)/g;
34901 
34902  double r=sqrt(pow((a_x-p_x),2)+pow((a_y-p_y),2));
34903 
34904  double rhalfca_x=0.5*(a_x-c_x);
34905  double rhalfca_y=0.5*(a_y-c_y);
34906 
34907  double halfca_squared=pow(rhalfca_x,2)+pow(rhalfca_y,2);
34908 
34909  double sticky_out_bit=r-sqrt(std::fabs((r*r) - halfca_squared));
34910 
34911  // If sticky out bit divided by distance between end nodes
34912  // is less than tolerance the boundary is so flat that we
34913  // can safely kill the node
34914  if ((sticky_out_bit/(2.0*sqrt(halfca_squared)))<
34915  unrefinement_tolerance)
34916  {
34917  do_it=true;
34918  if(check_only) {return true;}
34919  }
34920  }
34921 
34922  // If the vertex was proposed for deletion check that it is
34923  // allowed for being deleted
34924  if (do_it && boundary_receive_connections)
34925  {
34926  // Is the vertex one of the non deletable vertices
34927  for (std::set<Vector<double> >::iterator it = no_delete_vertex.begin();
34928  it != no_delete_vertex.end(); it++)
34929  {
34930  // Compute the distance between the proposed node to delete
34931  // and the ones that should not be deleted
34932  const double x = (*it)[0];
34933  const double y = (*it)[1];
34934  double error = (b_x - x)*(b_x - x) + (b_y - y)*(b_y - y);
34935  error = sqrt(error);
34936 
34937  if(error<ToleranceForVertexMismatchInPolygons::Tolerable_error)
34938  {
34939  // Do not delete the vertex
34940  do_it = false;
34941  break;
34942  }
34943 
34944  }
34945 
34946  } // if (do_it && boundary_receive_connections)
34947 
34948  // Remove node?
34949  if (do_it)
34950  {
34951  vector_bnd_vertices[i].resize(0);
34952  }
34953 
34954  // Increase the counter, that indicates the number of the
34955  // next middle node
34956  counter+=2;
34957  }
34958 
34959  // coming out of here the value of counter is the index of the
34960  // last node on the polyline counter=n_vertex-1 (in case of an
34961  // even number of nodes) or counter has the value of the number
34962  // of nodes on the polyline counter=n_vertex (in case of an odd
34963  // number of nodes
34964 
34965  // Special treatment for the end of the polyline:
34966  // If the number of nodes is even, then the previous loop stopped
34967  // at the last but second node, i.e. the current value of counter
34968  // is the index of the last node. If that's the case, the last but
34969  // one node needs to be treated separately
34970  if( (counter)==(n_vertex-1) )
34971  {
34972  // Set the last but one node as middle node
34973  unsigned i=vector_bnd_vertices.size()-2;
34974 
34975  // Index of the current! last but second node (considering any
34976  // previous deletion)
34977  unsigned n=0;
34978 
34979  if(vector_bnd_vertices[counter-2].size()!=0)
34980  {
34981  // if the initial last but second node does still exist then
34982  // this one is obviously also the current last but second one
34983  n=counter-2;
34984  }
34985  else
34986  {
34987  // if the initial last but second node was deleted then the
34988  // initial last but third node is the current last but second
34989  // node
34990  n=counter-3;
34991  }
34992 
34993  // CODE DUPLICATION -- CAN'T BE BOTHERED TO WRITE A SEPARATE
34994  // FUNCTION FOR THIS; PROBABLY WORTH DOING IF/WHEN THERE'S
34995  // A MISTAKE IN ANY OF THIS AND IT NEEDS TO BE FIXED...
34996 
34997  // Maths from http://www.cgafaq.info/wiki/Circle_Through_Three_Points
34998  double a_x=vector_bnd_vertices[n][1];
34999  double a_y=vector_bnd_vertices[n][2];
35000  double b_x=vector_bnd_vertices[i][1];
35001  double b_y=vector_bnd_vertices[i][2];
35002  double c_x=vector_bnd_vertices[i+1][1];
35003  double c_y=vector_bnd_vertices[i+1][2];
35004 
35005  double a=b_x-a_x;
35006  double b=b_y-a_y;
35007  double c=c_x-a_x;
35008  double d=c_y-a_y;
35009 
35010  double e=a*(a_x+b_x)+b*(a_y+b_y);
35011  double f=c*(a_x+c_x)+d*(a_y+c_y);
35012 
35013  double g=2.0*(a*(c_y-b_y)-b*(c_x-b_x));
35014 
35015  bool do_it=false;
35016  if (std::fabs(g)<1.0e-14)
35017  {
35018  do_it=true;
35019  if(check_only) {return true;}
35020  }
35021  else
35022  {
35023  double p_x=(d*e-b*f)/g;
35024  double p_y=(a*f-c*e)/g;
35025 
35026  double r=sqrt(pow((a_x-p_x),2)+pow((a_y-p_y),2));
35027 
35028  double rhalfca_x=0.5*(a_x-c_x);
35029  double rhalfca_y=0.5*(a_y-c_y);
35030 
35031  double halfca_squared=pow(rhalfca_x,2)+pow(rhalfca_y,2);
35032 
35033  double sticky_out_bit=r-sqrt(std::fabs((r*r) - halfca_squared));
35034 
35035  // If sticky out bit divided by distance between end nodes
35036  // is less than tolerance the boundary is so flat that we
35037  // can safely kill the node
35038  if ((sticky_out_bit/(2.0*sqrt(halfca_squared)))<
35039  unrefinement_tolerance)
35040  {
35041  do_it=true;
35042  if(check_only) {return true;}
35043  }
35044  }
35045 
35046  // If the vertex was proposed for deletion check that it is
35047  // allowed for being deleted
35048  if (do_it && boundary_receive_connections)
35049  {
35050  // Is the vertex one of the non deletable vertices
35051  for (std::set<Vector<double> >::iterator it = no_delete_vertex.begin();
35052  it != no_delete_vertex.end(); it++)
35053  {
35054  // Compute the distance between the proposed node to delete
35055  // and the ones that should not be deleted
35056  const double x = (*it)[0];
35057  const double y = (*it)[1];
35058  double error = (b_x - x)*(b_x - x) + (b_y - y)*(b_y - y);
35059  error = sqrt(error);
35060 
35061  if(error <
35062  ToleranceForVertexMismatchInPolygons::Tolerable_error)
35063  {
35064  // Do not delete the vertex
35065  do_it = false;
35066  break;
35067  }
35068 
35069  }
35070 
35071  } // if (do_it && boundary_receive_connections)
35072 
35073  // Remove node?
35074  if (do_it)
35075  {
35076  vector_bnd_vertices[i].resize(0);
35077  }
35078  }
35079 
35080  // Create another vector, which will only contain entries of
35081  // nodes that still exist
35082  Vector<Vector<double> > compact_vector;
35083  compact_vector.reserve(n_vertex);
35084  for (unsigned i=0;i<n_vertex;i++)
35085  {
35086  // If the entry was not deleted include it in the new vector
35087  if (vector_bnd_vertices[i].size()!=0)
35088  {
35089  compact_vector.push_back(vector_bnd_vertices[i]);
35090  }
35091  }
35092 
35093  /// Get the size of the vector that now includes all remaining nodes
35094  n_vertex =compact_vector.size();
35095 
35096  // If the size of the vector containing the remaining nodes is
35097  // different from the size of the vector before the unrefinement
35098  // routine (with the original nodes)
35099  // then the polyline was obviously updated
35100  if( n_vertex != vector_bnd_vertices.size() )
35101  {
35102  unrefinement_was_performed=true;
35103  }
35104 
35105  /// Copy back
35106  vector_bnd_vertices.resize(n_vertex);
35107  for(unsigned i=0;i<n_vertex;i++)
35108  {
35109  vector_bnd_vertices[i].resize(3);
35110  vector_bnd_vertices[i][0]=compact_vector[i][0];
35111  vector_bnd_vertices[i][1]=compact_vector[i][1];
35112  vector_bnd_vertices[i][2]=compact_vector[i][2];
35113  }
35114 
35115  return unrefinement_was_performed;
35116 
35117  }
35118 
35119 //=========================================================================
35120 /// \short Helper function that performs the refinement process
35121 /// on the specified boundary by using the provided vertices
35122 /// representation. Optional boolean is used to run it as test only (if
35123 /// true is specified as input) in which case vertex coordinates aren't
35124 /// actually modified. Returned boolean indicates if polyline was (or
35125 /// would have been -- if called with check_only=false) changed.
35126 //=========================================================================
35127 template<class ELEMENT>
35129 refine_boundary(Mesh* face_mesh_pt,
35130  Vector<Vector<double> > &vector_bnd_vertices,
35131  double &refinement_tolerance,
35132  const bool &check_only)
35133  {
35134  // Boolean that indicates whether an actual update of the vertex
35135  // coordinates was performed or not
35136  bool refinement_was_performed=false;
35137 
35138  // Create a geometric object from the mesh to represent
35139  //the curvilinear boundary
35140  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt);
35141 
35142  // Get the total number of current vertices
35143  unsigned n_vertex=vector_bnd_vertices.size();
35144 
35145  // Create a new (temporary) vector for the nodes, so
35146  // that new nodes can be stored
35147  Vector<Vector<double> > extended_vector;
35148 
35149  // Reserve memory space for twice the number of already
35150  // existing nodes (worst case)
35151  extended_vector.reserve(2*n_vertex);
35152 
35153  // Loop over the nodes until the last but one node
35154  for(unsigned inod=0;inod<n_vertex-1;inod++)
35155  {
35156  // Get local coordinate of "left" node
35157  double zeta_left=vector_bnd_vertices[inod][0];
35158 
35159  // Get position vector of "left" node
35160  Vector<double> R_left(2);
35161  for(unsigned i=0;i<2;i++)
35162  {
35163  R_left[i]=vector_bnd_vertices[inod][i+1];
35164  }
35165 
35166  // Get local coordinate of "right" node
35167  double zeta_right=vector_bnd_vertices[inod+1][0];
35168 
35169  // Get position vector of "right" node
35170  Vector<double> R_right(2);
35171  for(unsigned i=0;i<2;i++)
35172  {
35173  R_right[i]=vector_bnd_vertices[inod+1][i+1];
35174  }
35175 
35176  // Get the boundary coordinate of the midpoint
35177  Vector<double> zeta_mid(1);
35178  zeta_mid[0]=0.5*(zeta_left+zeta_right);
35179 
35180  // Get the position vector of the midpoint on the
35181  // curvilinear boundary
35182  Vector<double> R_mid(2);
35183  mesh_geom_obj_pt->position(zeta_mid,R_mid);
35184 
35185  // Get the position vector of the midpoint on the straight
35186  // line connecting "left" and "right" node
35187  Vector<double> R_mid_polygon(2);
35188  for(unsigned i=0;i<2;i++)
35189  {
35190  R_mid_polygon[i]=0.5*(R_right[i]+R_left[i]);
35191  }
35192 
35193  // Calculate the distance between the midpoint on the curvilinear
35194  // boundary and the midpoint on the straight line
35195  double distance=sqrt((R_mid[0]-R_mid_polygon[0])*
35196  (R_mid[0]-R_mid_polygon[0])+
35197  (R_mid[1]-R_mid_polygon[1])*
35198  (R_mid[1]-R_mid_polygon[1]));
35199 
35200  // Calculating the length of the straight line
35201  double length=sqrt((R_right[0]-R_left[0])*(R_right[0]-R_left[0])+
35202  (R_right[1]-R_left[1])*(R_right[1]-R_left[1]));
35203 
35204  // If the ratio of distance between the midpoints to the length
35205  // of the straight line is larger than the tolerance
35206  // specified for the criterion when points can be deleted,
35207  // create a new node and add it to the (temporary) vector
35208  if((distance/length) > refinement_tolerance)
35209  {
35210 
35211  if(check_only)
35212  {
35213  // Delete the allocated memory for the geometric object
35214  // that represents the curvilinear boundary
35215  delete mesh_geom_obj_pt;
35216  return true;
35217  }
35218 
35219  Vector<double> new_node(3);
35220  new_node[0]=zeta_mid[0];
35221  new_node[1]=R_mid[0];
35222  new_node[2]=R_mid[1];
35223 
35224  // Include the "left" node in the new "temporary" vector
35225  extended_vector.push_back(vector_bnd_vertices[inod]);
35226 
35227  // Include the new node as well
35228  extended_vector.push_back(new_node);
35229 
35230  }
35231  else
35232  {
35233  // Include the "left" node in the new "temporary" vector
35234  // and move on to the next node
35235  extended_vector.push_back(vector_bnd_vertices[inod]);
35236  }
35237  } // end of loop over nodes
35238 
35239  // Add the last node to the vector
35240  extended_vector.push_back(vector_bnd_vertices[n_vertex-1]);
35241 
35242  /// Get the size of the vector that now includes all added nodes
35243  n_vertex=extended_vector.size();
35244 
35245  // If the size of the vector including the added nodes is
35246  // different from the size of the vector before the refinement
35247  // routine then the polyline was obviously updated
35248  if( n_vertex != vector_bnd_vertices.size() )
35249  {
35250  refinement_was_performed=true;
35251  }
35252 
35253  // Copy across
35254  vector_bnd_vertices.resize(n_vertex);
35255  for(unsigned i=0;i<n_vertex;i++)
35256  {
35257  vector_bnd_vertices[i].resize(3);
35258  vector_bnd_vertices[i][0]=extended_vector[i][0];
35259  vector_bnd_vertices[i][1]=extended_vector[i][1];
35260  vector_bnd_vertices[i][2]=extended_vector[i][2];
35261  }
35262 
35263  // Delete the allocated memory for the geometric object
35264  // that represents the curvilinear boundary
35265  delete mesh_geom_obj_pt;
35266 
35267  return refinement_was_performed;
35268 
35269  }
35270 
35271  //=========================================================================
35272  // \short Helper function that applies the maximum length constraint
35273  // when it was specified. This will increase the number of points in
35274  // the current curve section in case that any segment on it does not
35275  // fulfils the requirement
35276  //=========================================================================
35277  template<class ELEMENT>
35279  apply_max_length_constraint(Mesh* face_mesh_pt,
35280  Vector<Vector<double> > &vector_bnd_vertices,
35281  double &max_length_constraint)
35282  {
35283  // Boolean that indicates whether an actual update of the vertex
35284  // coordinates was performed or not
35285  bool max_length_applied=false;
35286 
35287  // Create a geometric object from the mesh to represent
35288  //the curvilinear boundary
35289  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt);
35290 
35291  // Get the total number of current vertices
35292  unsigned n_vertex=vector_bnd_vertices.size();
35293 
35294  // Create a new (temporary) vector for the nodes, so
35295  // that new nodes can be stored
35296  Vector<Vector<double> > extended_vector;
35297 
35298  // Loop over the nodes until the last but one node
35299  for(unsigned inod=0;inod<n_vertex-1;inod++)
35300  {
35301  // Get local coordinate of "left" node
35302  double zeta_left=vector_bnd_vertices[inod][0];
35303 
35304  // Get position vector of "left" node
35305  Vector<double> R_left(2);
35306  for(unsigned i=0;i<2;i++)
35307  {
35308  R_left[i]=vector_bnd_vertices[inod][i+1];
35309  }
35310 
35311  // Get local coordinate of "right" node
35312  double zeta_right=vector_bnd_vertices[inod+1][0];
35313 
35314  // Get position vector of "right" node
35315  Vector<double> R_right(2);
35316  for(unsigned i=0;i<2;i++)
35317  {
35318  R_right[i]=vector_bnd_vertices[inod+1][i+1];
35319  }
35320 
35321  // Include the "left" node in the new "temporary" vector
35322  extended_vector.push_back(vector_bnd_vertices[inod]);
35323 
35324  // Check whether the current distance between the left and right node
35325  // is longer than the specified constraint or not
35326  double length=std::fabs(zeta_right-zeta_left);
35327 
35328  // Do we need to introduce new nodes?
35329  if (length > max_length_constraint)
35330  {
35331  double n_pts = length/max_length_constraint;
35332  // We only want the integer part
35333  unsigned n_points = static_cast<unsigned>(n_pts);
35334  double zeta_increment = (zeta_right-zeta_left)/((double)n_points+1);
35335 
35336  Vector<double> zeta(1);
35337  // Create the n_points+1 points inside the segment
35338  for(unsigned s=1;s<n_points+1;s++)
35339  {
35340  // Get the coordinates
35341  zeta[0]= zeta_left + zeta_increment*double(s);
35342  Vector<double> vertex(2);
35343  mesh_geom_obj_pt->position(zeta, vertex);
35344 
35345  // Create the new node
35346  Vector<double> new_node(3);
35347  new_node[0]=zeta[0];
35348  new_node[1]=vertex[0];
35349  new_node[2]=vertex[1];
35350 
35351  // Include the new node
35352  extended_vector.push_back(new_node);
35353  }
35354  }
35355  }
35356 
35357  // Add the last node to the vector
35358  extended_vector.push_back(vector_bnd_vertices[n_vertex-1]);
35359 
35360  /// Get the size of the vector that now includes all added nodes
35361  n_vertex=extended_vector.size();
35362 
35363  // If the size of the vector including the added nodes is
35364  // different from the size of the vector before applying the maximum length
35365  // constraint then the polyline was obviously updated
35366  if( n_vertex != vector_bnd_vertices.size() )
35367  {
35368  max_length_applied = true;
35369  }
35370 
35371  // Copy across
35372  vector_bnd_vertices.resize(n_vertex);
35373  for(unsigned i=0;i<n_vertex;i++)
35374  {
35375  vector_bnd_vertices[i].resize(3);
35376  vector_bnd_vertices[i][0]=extended_vector[i][0];
35377  vector_bnd_vertices[i][1]=extended_vector[i][1];
35378  vector_bnd_vertices[i][2]=extended_vector[i][2];
35379  }
35380 
35381  // Delete the allocated memory for the geometric object
35382  // that represents the curvilinear boundary
35383  delete mesh_geom_obj_pt;
35384 
35385  return max_length_applied;
35386 
35387  }
35388 
35389 //=========================================================================
35390 /// \short Helper function
35391 /// Creates an unsorted face mesh representation from the specified
35392 /// boundary id. It means that the elements are not sorted along the
35393 /// boundary
35394 //=========================================================================
35395 template<class ELEMENT>
35398  const unsigned &boundary_id,
35399  Mesh* face_mesh_pt)
35400  {
35401  // Create a face mesh adjacent to specified boundary.
35402  // The face mesh consists of FaceElements that may also be
35403  // interpreted as GeomObjects
35404 
35405  // Build the face mesh
35406  this->template build_face_mesh<ELEMENT,FaceElementAsGeomObject>
35407  (boundary_id,face_mesh_pt);
35408 
35409  // Find the total number of added elements
35410  unsigned n_element = face_mesh_pt->nelement();
35411  // Loop over the elements
35412  for(unsigned e=0;e<n_element;e++)
35413  {
35414 
35415  //Cast the element pointer to the correct thing!
35416  FaceElementAsGeomObject<ELEMENT>* el_pt=
35417  dynamic_cast<FaceElementAsGeomObject<ELEMENT>*>
35418  (face_mesh_pt->element_pt(e));
35419 
35420  // Set bulk boundary number
35421  el_pt->set_boundary_number_in_bulk_mesh(boundary_id);
35422 
35423  }
35424 
35425  }
35426 
35427 //=========================================================================
35428 /// \short Helper function
35429 /// Creates a sorted face mesh representation of the specified PolyLine
35430 /// It means that the elements are sorted along the boundary
35431 //=========================================================================
35432 template<class ELEMENT>
35435  const unsigned &boundary_id,
35436  Mesh* face_mesh_pt,
35437  std::map<FiniteElement*, bool> &is_inverted,
35438  bool &inverted_face_mesh)
35439  {
35440  Mesh *tmp_unsorted_face_mesh_pt = new Mesh();
35441 
35442  // First step we get the unsorted version of the face mesh
35443  create_unsorted_face_mesh_representation(
35444  boundary_id, tmp_unsorted_face_mesh_pt);
35445 
35446  // Once with the unsorted version of the face mesh
35447  // only left to sort it out!!!
35448 
35449  // Put all face elements in order
35450  //-------------------------------
35451 
35452  // Put first element into ordered list
35453  // Temporal list for sorting the elements
35454  std::list<FiniteElement*> sorted_el_pt;
35455  FiniteElement* el_pt = tmp_unsorted_face_mesh_pt->finite_element_pt(0);
35456  sorted_el_pt.push_back(el_pt);
35457 
35458  // Number of nodes
35459  unsigned nnod=el_pt->nnode();
35460 
35461  // Count elements that have been done
35462  unsigned count_done=0;
35463 
35464  // How many face elements are there?
35465  unsigned n_face_element = tmp_unsorted_face_mesh_pt->nelement();
35466 
35467  // Keep track of who's done
35468  std::map<FiniteElement*,bool> done_el;
35469 
35470  is_inverted.clear();
35471 
35472  // Fit in the other elements in at most nel^2 loops
35473  for (unsigned ee=1;ee<n_face_element;ee++)
35474  {
35475  // Loop over all elements to check if they fit to the right
35476  // or the left of the current one
35477  for (unsigned e=1;e<n_face_element;e++)
35478  {
35479  // Candidate element
35480  el_pt=tmp_unsorted_face_mesh_pt->finite_element_pt(e);
35481 
35482  // Is it done yet?
35483  if (!done_el[el_pt])
35484  {
35485  // Left and rightmost elements
35486  FiniteElement* first_el_pt=(*sorted_el_pt.begin());
35487  std::list<FiniteElement*>::iterator it=sorted_el_pt.end();
35488  it--;
35489  FiniteElement* last_el_pt=*it;
35490 
35491  // Left and rightmost nodes
35492  Node* left_node_pt=first_el_pt->node_pt(0);
35493  if (is_inverted[first_el_pt])
35494  {
35495  left_node_pt=first_el_pt->node_pt(nnod-1);
35496  }
35497  Node* right_node_pt=last_el_pt->node_pt(nnod-1);
35498  if (is_inverted[last_el_pt])
35499  {
35500  right_node_pt=last_el_pt->node_pt(0);
35501  }
35502 
35503  // New element fits at the left of first element and is not inverted
35504  if (left_node_pt==el_pt->node_pt(nnod-1))
35505  {
35506  sorted_el_pt.push_front(el_pt);
35507  done_el[el_pt]=true;
35508  count_done++;
35509  is_inverted[el_pt]=false;
35510  }
35511  // New element fits at the left of first element and is inverted
35512 
35513  else if (left_node_pt==el_pt->node_pt(0))
35514  {
35515  sorted_el_pt.push_front(el_pt);
35516  done_el[el_pt]=true;
35517  count_done++;
35518  is_inverted[el_pt]=true;
35519  }
35520  // New element fits on the right of last element and is not inverted
35521 
35522  else if(right_node_pt==el_pt->node_pt(0))
35523  {
35524  sorted_el_pt.push_back(el_pt);
35525  done_el[el_pt]=true;
35526  count_done++;
35527  is_inverted[el_pt]=false;
35528  }
35529  // New element fits on the right of last element and is inverted
35530 
35531  else if (right_node_pt==el_pt->node_pt(nnod-1))
35532  {
35533  sorted_el_pt.push_back(el_pt);
35534  done_el[el_pt]=true;
35535  count_done++;
35536  is_inverted[el_pt]=true;
35537  }
35538 
35539  if (done_el[el_pt])
35540  {
35541  break;
35542  }
35543  }
35544  }
35545  }
35546 
35547  // Are we done?
35548  if (count_done!=(n_face_element-1))
35549  {
35550  std::ostringstream error_message;
35551  error_message
35552  << "When ordering FaceElements on "
35553  << "boundary " << boundary_id << " only managed to order \n" << count_done
35554  << " of " << n_face_element << " face elements.\n"
35555  << std::endl;
35556  throw OomphLibError(
35557  error_message.str(),
35558  OOMPH_CURRENT_FUNCTION,
35559  OOMPH_EXCEPTION_LOCATION);
35560  }
35561 
35562  // Now make a mesh that contains the FaceElements in order
35563  // Remember that we currently have a list, not a mesh of sorted elements
35564 
35565  // Fill it
35566  for (std::list<FiniteElement*>::iterator it=sorted_el_pt.begin();
35567  it!=sorted_el_pt.end();it++)
35568  {
35569  // Get element
35570  FiniteElement* el_pt=*it;
35571 
35572  // add this face element to the order original mesh
35573  face_mesh_pt->add_element_pt(el_pt);
35574  }
35575 
35576  // Verify if face mesh representation is not inverted according to the
35577  // polyline specified by the user, it means that the initial and the
35578  // final vertex does really correspond to the first and last vertex
35579  // respectively, if not, state that the face mesh representation is
35580  // inverted
35581 
35582  // Get the associated polyline representation to the boundary
35583  TriangleMeshPolyLine *bnd_polyline =
35584  this->Boundary_curve_section_pt[boundary_id];
35585 
35586  // Get the really first vertex
35587  Vector<double> first_vertex =
35588  bnd_polyline->vertex_coordinate(0);
35589 
35590  // Now get the first node based on the face mesh representation
35591  // First get access to the first element
35592  FiniteElement* first_el_pt =
35593  face_mesh_pt->finite_element_pt(0);
35594 
35595  // Now get access to the first node
35596  unsigned n_node = first_el_pt->nnode();
35597  // Get the very first node (taking into account if it is
35598  // inverted or not!!)
35599  Node* first_node_pt = first_el_pt->node_pt(0);
35600  if (is_inverted[first_el_pt])
35601  {
35602  first_node_pt = first_el_pt->node_pt(n_node-1);
35603  }
35604 
35605  double error = (first_node_pt->x(0) - first_vertex[0])*
35606  (first_node_pt->x(0) - first_vertex[0]) +
35607  (first_node_pt->x(1) - first_vertex[1])*
35608  (first_node_pt->x(1) - first_vertex[1]);
35609 
35610  error = sqrt(error);
35611 
35612  if(error <
35613  ToleranceForVertexMismatchInPolygons::Tolerable_error)
35614  {
35615  inverted_face_mesh = false;
35616  }
35617  else
35618  {
35619  inverted_face_mesh = true;
35620  }
35621 
35622  }
35623 
35624 //=========================================================================
35625 /// Helper function to construct face mesh representation of all polylines,
35626 /// possibly with segments re-distributed between polylines
35627 /// to maintain an approximately even sub-division of the polygon
35628 //=========================================================================
35629 template<class ELEMENT>
35631 get_face_mesh_representation(TriangleMeshPolygon* polygon_pt,
35632  Vector<Mesh*>& face_mesh_pt)
35633  {
35634  // Number of polylines
35635  unsigned n_polyline = polygon_pt->npolyline();
35636  face_mesh_pt.resize(n_polyline);
35637 
35638  // Are we eligible for re-distributing polyline segments between
35639  // polylines? We're not if any of the boundaries are associated
35640  // with a GeomObject because we're then tied to the start and
35641  // end coordinates along it.
35642  bool eligible_for_segment_redistribution=true;
35643 
35644  // Loop over constituent polylines
35645  for(unsigned p=0;p<n_polyline;p++)
35646  {
35647 
35648  //Get the boundary id of the polyline
35649  unsigned bound =
35650  polygon_pt->polyline_pt(p)->boundary_id();
35651 
35652  //If the boundary has a geometric object representation then
35653  //we can't redistribute
35654  GeomObject* const geom_object_pt =
35655  this->boundary_geom_object_pt(bound);
35656  if(geom_object_pt!=0)
35657  {
35658  eligible_for_segment_redistribution=false;
35659  }
35660 
35661  face_mesh_pt[p] = new Mesh();
35662  create_unsorted_face_mesh_representation(
35663  bound, face_mesh_pt[p]);
35664 
35665  }
35666 
35667  if (!polygon_pt->is_redistribution_of_segments_between_polylines_enabled())
35668  {
35669  return;
35670  }
35671 
35672  //If there is more than one region we have to think... Die for now.
35673  if(this->nregion() > 1)
35674  {
35675  std::ostringstream warn_message;
35676  warn_message
35677  << "Can't currently re-distribute segments between polylines if there\n"
35678  << "are multiple regions; returning..." << std::endl;
35679  OomphLibWarning(warn_message.str(),
35680  "RefineableTriangleMesh::get_face_mesh_representation()",
35681  OOMPH_EXCEPTION_LOCATION);
35682  return;
35683  }
35684 
35685  // Redistribution overruled
35686  if (!eligible_for_segment_redistribution)
35687  {
35688  std::ostringstream warn_message;
35689  warn_message
35690  << "Over-ruling re-distribution of segments between polylines\n"
35691  << "because at least one boundary is associated with a GeomObject."
35692  << "Returning..." << std::endl;
35693  OomphLibWarning(warn_message.str(),
35694  "RefineableTriangleMesh::get_face_mesh_representation()",
35695  OOMPH_EXCEPTION_LOCATION);
35696  return;
35697  }
35698 
35699  // Create a vector for ordered face mesh
35700  Vector<Mesh*> ordered_face_mesh_pt(n_polyline);
35701 
35702  // Storage for the total arclength of polygon
35703  double s_total=0.0;
35704 
35705  // Storage for first and last nodes on polylines so we can figure
35706  // out if they are inverted relative to each other
35707  Vector<Node*> first_polyline_node_pt(n_polyline);
35708  Vector<Node*> last_polyline_node_pt(n_polyline);
35709  std::vector<bool> is_reversed(n_polyline,false);
35710 
35711  // Loop over constituent polylines
35712  for(unsigned p=0;p<n_polyline;p++)
35713  {
35714 
35715  // Put all face elements in order
35716  //-------------------------------
35717 
35718  // Put first element into ordered list
35719  std::list<FiniteElement*> ordered_el_pt;
35720  FiniteElement* el_pt=face_mesh_pt[p]->finite_element_pt(0);
35721  ordered_el_pt.push_back(el_pt);
35722 
35723  // Number of nodes
35724  unsigned nnod=el_pt->nnode();
35725 
35726  // Default for first and last node on polyline
35727  first_polyline_node_pt[p]=el_pt->node_pt(0);
35728  last_polyline_node_pt[p]=el_pt->node_pt(nnod-1);
35729 
35730  // Count elements that have been done
35731  unsigned count_done=0;
35732 
35733  // How many face elements are there?
35734  unsigned n_face_element = face_mesh_pt[p]->nelement();
35735 
35736  //Get the boundary id of the polyline
35737  unsigned bound =
35738  polygon_pt->polyline_pt(p)->boundary_id();
35739 
35740  // Keep track of who's done
35741  std::map<FiniteElement*,bool> done_el;
35742 
35743  // Keep track of which element is inverted
35744  std::map<FiniteElement*,bool> is_inverted;
35745 
35746  // Fit in the other elements in at most nel^2 loops
35747  for (unsigned ee=1;ee<n_face_element;ee++)
35748  {
35749  // Loop over all elements to check if they fit to the right
35750  // or the left of the current one
35751  for (unsigned e=1;e<n_face_element;e++)
35752  {
35753  // Candidate element
35754  el_pt=face_mesh_pt[p]->finite_element_pt(e);
35755 
35756  // Is it done yet?
35757  if (!done_el[el_pt])
35758  {
35759  // Left and rightmost elements
35760  FiniteElement* first_el_pt=(*ordered_el_pt.begin());
35761  std::list<FiniteElement*>::iterator it=ordered_el_pt.end();
35762  it--;
35763  FiniteElement* last_el_pt=*it;
35764 
35765  // Left and rightmost nodes
35766  Node* left_node_pt=first_el_pt->node_pt(0);
35767  if (is_inverted[first_el_pt])
35768  {
35769  left_node_pt=first_el_pt->node_pt(nnod-1);
35770  }
35771  Node* right_node_pt=last_el_pt->node_pt(nnod-1);
35772  if (is_inverted[last_el_pt])
35773  {
35774  right_node_pt=last_el_pt->node_pt(0);
35775  }
35776 
35777  // New element fits at the left of first element and is not inverted
35778  if (left_node_pt==el_pt->node_pt(nnod-1))
35779  {
35780  ordered_el_pt.push_front(el_pt);
35781  done_el[el_pt]=true;
35782  count_done++;
35783  is_inverted[el_pt]=false;
35784  first_polyline_node_pt[p]=el_pt->node_pt(0);
35785  }
35786  // New element fits at the left of first element and is inverted
35787 
35788  else if (left_node_pt==el_pt->node_pt(0))
35789  {
35790  ordered_el_pt.push_front(el_pt);
35791  done_el[el_pt]=true;
35792  count_done++;
35793  is_inverted[el_pt]=true;
35794  first_polyline_node_pt[p]=el_pt->node_pt(nnod-1);
35795  }
35796  // New element fits on the right of last element and is not inverted
35797 
35798  else if(right_node_pt==el_pt->node_pt(0))
35799  {
35800  ordered_el_pt.push_back(el_pt);
35801  done_el[el_pt]=true;
35802  count_done++;
35803  is_inverted[el_pt]=false;
35804  last_polyline_node_pt[p]=el_pt->node_pt(nnod-1);
35805  }
35806  // New element fits on the right of last element and is inverted
35807 
35808  else if (right_node_pt==el_pt->node_pt(nnod-1))
35809  {
35810  ordered_el_pt.push_back(el_pt);
35811  done_el[el_pt]=true;
35812  count_done++;
35813  is_inverted[el_pt]=true;
35814  last_polyline_node_pt[p]=el_pt->node_pt(0);
35815  }
35816 
35817  if (done_el[el_pt])
35818  {
35819  break;
35820  }
35821  }
35822  }
35823  }
35824 
35825  // Are we done?
35826  if (count_done!=(n_face_element-1))
35827  {
35828  std::ostringstream error_message;
35829  error_message
35830  << "When ordering FaceElements on "
35831  << "boundary " << bound << " only managed to order \n" << count_done
35832  << " of " << n_face_element << " face elements.\n"
35833  << std::endl;
35834  throw OomphLibError(
35835  error_message.str(),
35836  OOMPH_CURRENT_FUNCTION,
35837  OOMPH_EXCEPTION_LOCATION);
35838  }
35839 
35840  // Now make a mesh that contains the FaceElements in order
35841  ordered_face_mesh_pt[p] = new Mesh;
35842 
35843  // Fill it
35844  for (std::list<FiniteElement*>::iterator it=ordered_el_pt.begin();
35845  it!=ordered_el_pt.end();it++)
35846  {
35847  // Get element
35848  FiniteElement* el_pt=*it;
35849 
35850  // add this face element to the order original mesh
35851  ordered_face_mesh_pt[p]->add_element_pt(el_pt);
35852  }
35853 
35854  //Get the arclength along the polygon
35855  for(unsigned e=0;e<n_face_element;++e)
35856  {
35857  FiniteElement* el_pt=ordered_face_mesh_pt[p]->finite_element_pt(e);
35858  unsigned n_node=el_pt->nnode();
35859  double element_length_squared=0.0;
35860  for(unsigned i=0;i<2;i++)
35861  {
35862  element_length_squared += pow(el_pt->node_pt(n_node-1)->x(i)-
35863  el_pt->node_pt(0)->x(i),2);
35864  }
35865 
35866  // Determine element length
35867  double element_length=sqrt(element_length_squared);
35868 
35869  // Add this length to the total arclength
35870  s_total += element_length;
35871  }
35872 
35873  // Empty the original meshes
35874  face_mesh_pt[p]->flush_element_and_node_storage();
35875  }
35876 
35877  // Is first one reversed?
35878  if ((last_polyline_node_pt[0]==first_polyline_node_pt[1])||
35879  (last_polyline_node_pt[0]==last_polyline_node_pt[1]))
35880  {
35881  is_reversed[0]=false;
35882  }
35883  else if ((first_polyline_node_pt[0]==first_polyline_node_pt[1])||
35884  (first_polyline_node_pt[0]==last_polyline_node_pt[1]))
35885  {
35886  is_reversed[0]=true;
35887  }
35888 
35889  // Reorder the face meshes so that they are contiguous
35890  Vector<Mesh*> tmp_face_mesh_pt(n_polyline);
35891  std::vector<bool> mesh_done(n_polyline,false);
35892  Vector<unsigned> old_polyline_number(n_polyline);
35893 
35894  // Initial entry
35895  tmp_face_mesh_pt[0]=ordered_face_mesh_pt[0];
35896  unsigned current=0;
35897  old_polyline_number[0]=0;
35898  unsigned count_found=0;
35899 
35900  // Fill in the next entries
35901  for(unsigned p=1;p<n_polyline;p++)
35902  {
35903  Node* end_node_pt=last_polyline_node_pt[current];
35904  if (is_reversed[current])
35905  {
35906  end_node_pt=first_polyline_node_pt[current];
35907  }
35908 
35909  // Loop over all remaining face meshes to see which one fits
35910  for(unsigned pp=1;pp<n_polyline;pp++)
35911  {
35912  if (!mesh_done[pp])
35913  {
35914  // Current one is not reversed, candidate is not reversed
35915  if ((!is_reversed[current])&&
35916  (end_node_pt==first_polyline_node_pt[pp]))
35917  {
35918  tmp_face_mesh_pt[p]=ordered_face_mesh_pt[pp];
35919  mesh_done[pp]=true;
35920  is_reversed[pp]=false;
35921  old_polyline_number[p]=pp;
35922  current=pp;
35923  count_found++;
35924  break;
35925  }
35926  // Current one is not reversed, candidate is reversed
35927 
35928  else if ((!is_reversed[current])&&
35929  (end_node_pt==last_polyline_node_pt[pp]))
35930  {
35931  tmp_face_mesh_pt[p]=ordered_face_mesh_pt[pp];
35932  mesh_done[pp]=true;
35933  is_reversed[pp]=true;
35934  old_polyline_number[p]=pp;
35935  current=pp;
35936  count_found++;
35937  break;
35938  }
35939  // Current one is reversed, candidate is not reversed
35940 
35941  else if ((is_reversed[current])&&
35942  (end_node_pt==first_polyline_node_pt[pp]))
35943  {
35944  tmp_face_mesh_pt[p]=ordered_face_mesh_pt[pp];
35945  mesh_done[pp]=true;
35946  is_reversed[pp]=false;
35947  old_polyline_number[p]=pp;
35948  current=pp;
35949  count_found++;
35950  break;
35951  }
35952  // Current one is reversed, candidate is reversed
35953 
35954  else if ((is_reversed[current])&&
35955  (end_node_pt==last_polyline_node_pt[pp]))
35956  {
35957  tmp_face_mesh_pt[p]=ordered_face_mesh_pt[pp];
35958  mesh_done[pp]=true;
35959  is_reversed[pp]=true;
35960  old_polyline_number[p]=pp;
35961  current=pp;
35962  count_found++;
35963  break;
35964  }
35965  }
35966  }
35967  }
35968 
35969 #ifdef PARANOID
35970  if (count_found!=n_polyline-1)
35971  {
35972  std::ostringstream error_message;
35973  error_message << "Only found " << count_found
35974  << " out of " << n_polyline-1
35975  << " polylines to be fitted in.\n";
35976  throw OomphLibError(
35977  error_message.str(),
35978  OOMPH_CURRENT_FUNCTION,
35979  OOMPH_EXCEPTION_LOCATION);
35980  }
35981 #endif
35982 
35983  // Now overwrite the re-ordered data
35984  for (unsigned i=0;i<n_polyline;i++)
35985  {
35986  ordered_face_mesh_pt[i]=tmp_face_mesh_pt[i];
35987  }
35988 
35989  // Now do an approximate equidistribution of polylines
35990  //----------------------------------------------------
35991  double s=0.0;
35992  unsigned new_face_id=0;
35993 
35994  // Matrix map to indicate if node must not be removed from specified
35995  // boundary (!=0) or not (=0). Initialises itself to zero
35996  std::map<Node*,std::map<unsigned,unsigned> >
35997  node_must_not_be_removed_from_boundary_flag;
35998 
35999  // Loop over the old face mesh
36000  for(unsigned p=0;p<n_polyline;p++)
36001  {
36002  // Loop over the face elements
36003  unsigned n_face_element = ordered_face_mesh_pt[p]->nelement();
36004  for (unsigned e=0;e<n_face_element;e++)
36005  {
36006  unsigned el_number=e;
36007  if (is_reversed[p])
36008  {
36009  el_number=n_face_element-e-1;
36010  }
36011 
36012  FiniteElement* el_pt=
36013  ordered_face_mesh_pt[p]->finite_element_pt(el_number);
36014  unsigned n_node = el_pt->nnode();
36015 
36016  // Determine element length
36017  double element_length_squared=0.0;
36018  for(unsigned i=0;i<2;i++)
36019  {
36020  element_length_squared += pow(el_pt->node_pt(n_node-1)->x(i)-
36021  el_pt->node_pt(0)->x(i),2);
36022  }
36023  double element_length=sqrt(element_length_squared);
36024 
36025  // Add this length to the total arclength
36026  s += element_length;
36027 
36028  // Check if the current 'arclength' is less than the
36029  // whole 'arclength' divided by the number of polylines
36030  if(s < s_total/double(n_polyline)+1e-6)
36031  {
36032  // If so add this face element to the new face mesh
36033  face_mesh_pt[new_face_id]->add_element_pt(el_pt);
36034 
36035  unsigned bound_old =
36036  polygon_pt->polyline_pt(old_polyline_number[p])->boundary_id();
36037 
36038  unsigned bound_new =
36039  polygon_pt->polyline_pt(new_face_id)->boundary_id();
36040 
36041  // Loop over the nodes in the element
36042  for(unsigned i=0;i<n_node;i++)
36043  {
36044  // Get the pointer to the node
36045  Node* nod_pt=el_pt->node_pt(i);
36046 
36047  // If the two boundary id's are different, the face element's nodes
36048  // have to be added to the new boundary
36049  if(bound_new != bound_old)
36050  {
36051  // Add it to the new boundary
36052  add_boundary_node(bound_new,nod_pt);
36053 
36054  // We are happy for this node to be removed from the
36055  // old boundary?
36056  node_must_not_be_removed_from_boundary_flag[nod_pt][bound_old]+=0;
36057  }
36058 
36059  // If the face element hasn't moved, its nodes MUST remain
36060  // on that boundary (incl. any nodes that ar shared by
36061  // FaceElements that have moved (see above)
36062 
36063  else
36064  {
36065  node_must_not_be_removed_from_boundary_flag[nod_pt][bound_old]+=1;
36066  }
36067  }
36068  }
36069 
36070  // If not, reset the current 'arclength' to zero,
36071  // increase the new face id by one and go one element
36072  // back by decreasing e by one to make sure the current
36073  // element gets added to the next face mesh
36074 
36075  else
36076  {
36077  if(new_face_id!=n_polyline-1)
36078  {
36079  s=0.0;
36080  new_face_id++;
36081  --e;
36082  }
36083  else
36084  {
36085  s=0.0;
36086  --e;
36087  }
36088  }
36089  }
36090  } // end of loop over all polylines -- they are now re-distributed
36091 
36092 
36093  // Loop over all nodes on the boundaries of the polygon to remove
36094  // nodes from boundaries they are no longer on
36095  unsigned move_count=0;
36096  for (std::map<Node*,std::map<unsigned,unsigned> >::iterator
36097  it=node_must_not_be_removed_from_boundary_flag.begin();
36098  it!=node_must_not_be_removed_from_boundary_flag.end();it++)
36099  {
36100  // Get the node
36101  Node* nod_pt=(*it).first;
36102 
36103  // Now we loop over the boundaries that this node is on
36104  for (std::map<unsigned,unsigned>::iterator
36105  it_2=(*it).second.begin();it_2!=(*it).second.end();it_2++)
36106  {
36107  // Get the boundary id
36108  unsigned bound=(*it_2).first;
36109 
36110  // Remove it from that boundary?
36111  if((*it_2).second==0)
36112  {
36113  remove_boundary_node(bound,nod_pt);
36114  move_count++;
36115  }
36116  }
36117  }
36118 
36119  // Loop over the new face mesh to assign new boundary IDs
36120  for(unsigned p=0;p<n_polyline;p++)
36121  {
36122  //Get the boundary id of the polyline
36123  unsigned bound =
36124  polygon_pt->polyline_pt(p)->boundary_id();
36125 
36126  // Loop over the face elements
36127  unsigned n_face_element = face_mesh_pt[p]->nelement();
36128  for(unsigned e=0;e<n_face_element;e++)
36129  {
36130  //Cast the element pointer to the correct thing!
36131  FaceElementAsGeomObject<ELEMENT>* el_pt=
36132  dynamic_cast<FaceElementAsGeomObject<ELEMENT>*>
36133  (face_mesh_pt[p]->element_pt(e));
36134 
36135  // Set bulk boundary number
36136  el_pt->set_boundary_number_in_bulk_mesh(bound);
36137  }
36138  }
36139 
36140  // Update look-up for elements next to boundary
36141  setup_boundary_element_info();
36142 
36143  // Now re-create the boundary coordinates
36144  for(unsigned p=0;p<n_polyline;p++)
36145  {
36146  //Get the boundary id of the polyline
36147  unsigned bound =
36148  polygon_pt->polyline_pt(p)->boundary_id();
36149 
36150  // Do it
36151  this->template setup_boundary_coordinates<ELEMENT>(bound);
36152  }
36153 
36154  // Clean up
36155  for(unsigned p=0;p<n_polyline;p++)
36156  {
36157  // Flush the nodes from the face mesh to make sure we
36158  // don't delete them (the face mesh that we're returning from here
36159  // still needs them!)
36160  ordered_face_mesh_pt[p]->flush_element_and_node_storage();
36161  delete ordered_face_mesh_pt[p];
36162  }
36163 
36164  }
36165 
36166 //=========================================================================
36167 /// Helper function to construct face mesh representation of all polylines
36168 //=========================================================================
36169 template<class ELEMENT>
36172  TriangleMeshOpenCurve* open_polyline_pt,
36173  Vector<Mesh*>& face_mesh_pt)
36174 {
36175  // Number of polylines
36176  unsigned n_polyline = open_polyline_pt->ncurve_section();
36177  face_mesh_pt.resize(n_polyline);
36178 
36179  // Loop over constituent polylines
36180  for(unsigned p=0;p<n_polyline;p++)
36181  {
36182 
36183  //Get the boundary id of the polyline
36184  unsigned bound =
36185  open_polyline_pt->curve_section_pt(p)->boundary_id();
36186 
36187  face_mesh_pt[p] = new Mesh();
36188  create_unsorted_face_mesh_representation(
36189  bound, face_mesh_pt[p]);
36190 
36191  }
36192 
36193 }
36194 
36195 //======================================================================
36196 /// Update the PSLG that define the inner boundaries of the mesh.
36197 ///Optional boolean is used to run it as test only (if
36198 /// true is specified as input) in which case PSLG isn't actually
36199 /// modified. Returned boolean indicates if PSLG was (or would have
36200 /// been -- if called with check_only=false) changed.
36201 //======================================================================
36202 template <class ELEMENT>
36205  &internal_point_coord,
36206  const bool& check_only)
36207  {
36208  //Boolean to indicate whether an actual update of the internal
36209  // holes was performed
36210  bool update_was_performed=false;
36211  //Loop over the number of internal boundaries
36212  unsigned n_hole = internal_point_coord.size();
36213  for(unsigned ihole=0;ihole<n_hole;ihole++)
36214  {
36215  //Cache the pointer to the polygon representation
36216  TriangleMeshPolygon* const poly_pt
36217  = this->Internal_polygon_pt[ihole];
36218 
36219 
36220  //Can the polygon update its own configuration, in which case this
36221  //is easy
36222  if(poly_pt->can_update_reference_configuration())
36223  {
36224  poly_pt->reset_reference_configuration();
36225 
36226  // Initialize Vector hole_coordinates
36227  internal_point_coord[ihole].resize(2);
36228 
36229  // Get the vector of hole coordinates
36230  internal_point_coord[ihole]=poly_pt->internal_point();
36231  }
36232  //Otherwise we have to work much harder
36233 
36234  else
36235  {
36236  //if we only want to check whether an update of the inner
36237  //hole is necessary
36238  if(check_only)
36239  {
36240  //is it necessary?
36241  bool update_necessary=
36242  this->update_polygon_using_face_mesh(poly_pt,check_only);
36243 
36244  //Yes?
36245  if(update_necessary)
36246  {
36247  //then we have to adaptand return 'true'
36248  return true;
36249  }
36250  }
36251  //if we not only want to check, then we actually perform
36252  //the update
36253  else
36254  {
36255  update_was_performed=
36256  this->update_polygon_using_face_mesh(poly_pt);
36257  }
36258 
36259  //Now we need to sort out the hole coordinates
36260  if (!poly_pt->internal_point().empty())
36261  {
36262  //If fixed don't update and simply
36263  //Read out the existing value
36264  if(poly_pt->is_internal_point_fixed())
36265  {
36266  // Get the vector of hole coordinates
36267  internal_point_coord[ihole]=poly_pt->internal_point();
36268  }
36269  //This is where the work starts and this could be made much
36270  //better than the current hack
36271  else
36272  {
36273  //If the user has set their own function then use that
36274  if(this->Internal_hole_point_update_fct_pt!=0)
36275  {
36276  this->Internal_hole_point_update_fct_pt(ihole,poly_pt);
36277  }
36278  //Otherwise use our clunky default
36279  else
36280  {
36281  //Now sort out the hole coordinates
36282  Vector<double> vertex_coord;
36283  unsigned n_polyline = poly_pt->npolyline();
36284 
36285  // Initialize Vector hole_coordinates
36286  vertex_coord.resize(2);
36287  internal_point_coord[ihole].resize(2);
36288 
36289  //Hole centre will be found by averaging the position of
36290  //all vertex nodes
36291  internal_point_coord[ihole][0] = 0.0;
36292  internal_point_coord[ihole][1] = 0.0;
36293 
36294  for(unsigned p=0;p<n_polyline;p++)
36295  {
36296  Vector<double> poly_ave(2,0.0);
36297  //How many vertices are there in the segment
36298  unsigned n_vertex = poly_pt->polyline_pt(p)->nvertex();
36299  for(unsigned v=0;v<n_vertex;v++)
36300  {
36301  vertex_coord = poly_pt->polyline_pt(p)->vertex_coordinate(v);
36302  for(unsigned i=0;i<2;i++)
36303  {
36304  poly_ave[i] += vertex_coord[i];
36305  }
36306  }
36307 
36308  //Add the average polyline coordinate to the hole centre
36309  for(unsigned i=0;i<2;i++)
36310  {
36311  internal_point_coord[ihole][i] += poly_ave[i]/n_vertex;
36312  }
36313  }
36314 
36315  //Now average out the hole centre
36316  for(unsigned i=0;i<2;i++)
36317  {
36318  internal_point_coord[ihole][i] /= n_polyline;
36319  }
36320 
36321  //We have now found the hole centre stored in internal_point_coordinate[ihole][i]
36322 
36323  //Find polylines that intersect at y average value
36324  //Alice's version but this does not work if the end point of a
36325  //segment is the intersection point (i.e. at the y average value)
36326  /*Vector<double> vertex_coord2;
36327  unsigned n_intersect=0;
36328  double x_average=0.0;
36329 
36330  for(unsigned p=0;p<n_polyline;p++)
36331  {
36332  //How many vertices are there in the segment
36333  unsigned n_vertex = poly_pt->polyline_pt(p)->nvertex();
36334  for(unsigned v=0;v<n_vertex-1;v++)
36335  {
36336  vertex_coord = poly_pt->polyline_pt(p)->vertex_coordinate(v);
36337  vertex_coord2 = poly_pt->polyline_pt(p)->vertex_coordinate(v+1);
36338  std::cout << vertex_coord[0] << " " << vertex_coord[1]
36339  << " " <<
36340  vertex_coord2[0] << " " <<
36341 
36342  vertex_coord2[1] << "\n";
36343  //Does the line between vertices intersect the vertical position
36344  if((vertex_coord[1] -internal_point_coord[ihole][1])*
36345  (vertex_coord2[1] - internal_point_coord[ihole][1]) < 0.0)
36346  {
36347  ++n_intersect; x_average += 0.5*(vertex_coord[0] + vertex_coord2[0]);
36348  }
36349  }
36350  }
36351 
36352  //Now just report the value if we have had intersections
36353  if(n_intersect != 0)
36354  {
36355  //Report
36356  std::cout << "I have computed a hole " << x_average << " " << n_intersect << " "
36357  << x_average/((double)n_intersect) << std::endl;
36358  internal_point_coord[ihole][0] = x_average/((double)n_intersect);
36359  }
36360  */
36361 
36362  //Set the new hole centre
36363  poly_pt->internal_point() = internal_point_coord[ihole];
36364  //std::cout << "I've had my centre updated to "
36365  // << internal_point_coord[ihole][0]
36366  // << " " << internal_point_coord[ihole][1] << "\n";
36367  }
36368  }
36369 
36370  }
36371  }
36372  } //End of the action (n_hole for)
36373 
36374  if(check_only)
36375  {
36376  // If we make it up to here and we only check then no update is required
36377  return false;
36378  }
36379  else
36380  {
36381  // otherwise indicate whether an actual update was performed
36382  return update_was_performed;
36383  }
36384 
36385  } //End of the loop of internal boundaries
36386 
36387  //======================================================================
36388  /// Create the polylines and fill associate data structures, used when
36389  /// creating from a mesh from polyfiles
36390  //======================================================================
36391  template<class ELEMENT>
36393  create_polylines_from_polyfiles(const std::string& node_file_name,
36394  const std::string& poly_file_name)
36395  {
36396  // Get the nodes coordinates (the index of the nodes to build the
36397  // polylines is the one used in the node_file_name file)
36398  // Process node file
36399  // -----------------
36400  std::ifstream node_file(node_file_name.c_str(),std::ios_base::in);
36401 
36402  // Check that the file actually opened correctly
36403  if(!node_file.is_open())
36404  {
36405  std::string error_msg("Failed to open node file: ");
36406  error_msg += "\"" + node_file_name + "\".";
36407  throw OomphLibError(error_msg, OOMPH_CURRENT_FUNCTION,
36408  OOMPH_EXCEPTION_LOCATION);
36409  }
36410 
36411  // Read number of nodes
36412  unsigned nnodes;
36413  node_file >> nnodes;
36414 
36415  // Spatial dimension of nodes
36416  unsigned dimension;
36417  node_file >> dimension;
36418 
36419 #ifdef PARANOID
36420  if(dimension!=2)
36421  {
36422  throw OomphLibError("The dimension must be 2\n",
36423  OOMPH_CURRENT_FUNCTION,
36424  OOMPH_EXCEPTION_LOCATION);
36425  }
36426 #endif
36427 
36428  // Storage the nodes vertices
36429  Vector<double> x_node(nnodes);
36430  Vector<double> y_node(nnodes);
36431 
36432  // Number of attributes
36433  unsigned npoint_attributes;
36434  node_file >> npoint_attributes;;
36435 
36436  // Flag for boundary markers
36437  unsigned boundary_markers_flag=0;
36438  node_file >> boundary_markers_flag;
36439 
36440  // Dummy for node number
36441  unsigned dummy_node_number;
36442  // Dummy for node attribute
36443  unsigned dummy_node_attribute;
36444  // Dummy for node boundary
36445  unsigned dummy_node_boundary;
36446 
36447  // Load in nodal posititions, point attributes
36448  // and boundary markers
36449  for(unsigned i=0;i<nnodes;i++)
36450  {
36451  node_file>>dummy_node_number;
36452  node_file>>x_node[i];
36453  node_file>>y_node[i];
36454  for(unsigned j=0;j<npoint_attributes;++j)
36455  {
36456  node_file>>dummy_node_attribute;
36457  }
36458  if(boundary_markers_flag)
36459  {
36460  node_file>>dummy_node_boundary;
36461  }
36462  }
36463  node_file.close();
36464 
36465  // Get the segments information and use that info. to create the
36466  // polylines
36467 
36468  // A map to store the segments associated to a boundary, non sorted
36469  std::map<unsigned,Vector<std::pair<unsigned,unsigned> > >
36470  unsorted_boundary_segments;
36471 
36472  // Independent storage for the boundaries ids found in the segments so that
36473  // the polylines, and therefore polygons be created in the order they appear
36474  // in the polyfile
36475  Vector<unsigned> sorted_boundaries_ids;
36476 
36477  // Process poly file to extract edges
36478  //-----------------------------------
36479 
36480  // Open poly file
36481  std::ifstream poly_file(poly_file_name.c_str(),std::ios_base::in);
36482 
36483  // Check that the file actually opened correctly
36484  if(!poly_file.is_open())
36485  {
36486  std::string error_msg("Failed to open poly file: ");
36487  error_msg += "\"" + poly_file_name + "\".";
36488  throw OomphLibError(error_msg, OOMPH_CURRENT_FUNCTION,
36489  OOMPH_EXCEPTION_LOCATION);
36490  }
36491 
36492  // Number of nodes in poly file --- these will be ignore
36493  unsigned n_node_poly;
36494  poly_file >> n_node_poly;
36495 
36496  // Dimension
36497  poly_file >> dimension;
36498 
36499  // Attribute flag
36500  unsigned attribute_flag;
36501  poly_file >> attribute_flag;
36502 
36503  // Flag for boundary markers
36504  poly_file >> boundary_markers_flag;
36505 
36506  // Ignore node information: Note: No, we can't extract the
36507  // actual nodes themselves from here!
36508  unsigned dummy;
36509  for(unsigned i=0;i<n_node_poly;i++)
36510  {
36511  //Read in (and discard) node number and x and y coordinates
36512  poly_file>>dummy;
36513  poly_file>>dummy;
36514  poly_file>>dummy;
36515  //read in the attributes
36516  for(unsigned j=0;j<attribute_flag;++j)
36517  {
36518  poly_file >> dummy;
36519  }
36520  //read in the boundary marker
36521  if(boundary_markers_flag==1)
36522  {
36523  poly_file>>dummy;
36524  }
36525  }
36526 
36527  // Variable used to read the values from the input file
36528  unsigned read_value;
36529 
36530  // Number of segments
36531  poly_file >> read_value;
36532  const unsigned nglobal_segments = read_value;
36533 
36534  // Boundary marker flag
36535  poly_file >> boundary_markers_flag;
36536 
36537  // Global segment number
36538  unsigned global_segment_number;
36539 
36540  // Node identifier set (used to identify possible internal boundaries)
36541  std::set<unsigned> nodes_ids;
36542 
36543  // Extract information for each segment
36544  for(unsigned i=0;i<nglobal_segments;i++)
36545  {
36546  // Node id on the edge of the segment
36547  unsigned lnode_id=0; // left node
36548  unsigned rnode_id=0; // right node
36549  unsigned bnd_id=0; // boundary id associated to the current segment
36550  poly_file >> global_segment_number;
36551  poly_file >> lnode_id;
36552  poly_file >> rnode_id;
36553  nodes_ids.insert(lnode_id);
36554  nodes_ids.insert(rnode_id);
36555  if(boundary_markers_flag)
36556  {
36557  poly_file >> bnd_id;
36558  }
36559 
36560  // Store the segments info. (use bnd_id - 1 because the nodes and
36561  // elements associated the bnd_id have been associated by external
36562  // methods to bnd_id - 1)
36563  unsorted_boundary_segments[bnd_id-1].push_back(
36564  std::make_pair(lnode_id, rnode_id));
36565 
36566  // Add the boundary id to the vector of boundaries ids only if it
36567  // has not been added, the polylines will be created using this
36568  // order
36569 
36570  // Get the number of boundaries ids currently sorted
36571  const unsigned nsorted_boundaries_ids =
36572  sorted_boundaries_ids.size();
36573  // Flag to know if the boundary id was found
36574  bool boundary_id_found = false;
36575  for (unsigned ib = 0; ib < nsorted_boundaries_ids; ib++)
36576  {
36577  if (sorted_boundaries_ids[ib] == bnd_id - 1)
36578  {
36579  boundary_id_found = true;
36580  break;
36581  } // if (sorted_boundaries_ids[ib] == bnd_id - 1)
36582  } // for (ib < nsorted_boundaries_ids)
36583 
36584  // If th boundary id has not been added, then add it!!!
36585  if (!boundary_id_found)
36586  {
36587  sorted_boundaries_ids.push_back(bnd_id - 1);
36588  } // if (!boundary_id_found)
36589 
36590  }
36591 
36592  // Verify if there are internal boundaries defined, if that is the
36593  // case we can not continue since we are not yet supporting internal
36594  // boundaries defined in polyfiles to created a mesh that may be
36595  // adapted
36596 #ifdef PARANOID
36597  if (nglobal_segments != nodes_ids.size())
36598  {
36599  std::ostringstream error_message;
36600  error_message
36601  << "The number of nodes (" << nodes_ids.size() << ") and segments ("
36602  << nglobal_segments << ") is different.\nThis may mean that there "
36603  << "are internal non-closed boundaries defined in\nthe polyfile. "
36604  << "If you need this feature please use the TriangleMeshPoyLine\n"
36605  << "and TriangleMeshCurviLine objects to define your domain.\n\n";
36606  throw OomphLibError(error_message.str(),
36607  OOMPH_CURRENT_FUNCTION,
36608  OOMPH_EXCEPTION_LOCATION);
36609  }
36610 #endif
36611 
36612  // Now sort the segments associated to a boundary to create a contiguous
36613  // polyline, but first check that the number of found boundaries be the
36614  // same as the current number of boundaries in the mesh
36615  const unsigned nboundary = unsorted_boundary_segments.size();
36616 
36617 #ifdef PARANOID
36618  if (nboundary != this->nboundary())
36619  {
36620  std::ostringstream error_message;
36621  error_message
36622  << "The number of boundaries on the mesh (" << this->nboundary()
36623  << ") is different from the number of\nboundaries read from the "
36624  << "polyfiles (" << unsorted_boundary_segments.size() << ")!!!\n\n\n";
36625  throw OomphLibError(error_message.str(),
36626  OOMPH_CURRENT_FUNCTION,
36627  OOMPH_EXCEPTION_LOCATION);
36628  }
36629 #endif
36630 
36631  // Get the number of sorted boundaries ids and check that it matches
36632  // with the total number of boundaries
36633  const unsigned nsorted_boundaries_ids =
36634  sorted_boundaries_ids.size();
36635 #ifdef PARANOID
36636  if (nsorted_boundaries_ids != this->nboundary())
36637  {
36638  std::ostringstream error_message;
36639  error_message
36640  << "The number of boundaries on the mesh (" << this->nboundary()
36641  << ") is different from the number of\nsorted boundaries ids read "
36642  << "from the polyfiles (" << nsorted_boundaries_ids << ")!!!\n\n\n";
36643  throw OomphLibError(error_message.str(),
36644  OOMPH_CURRENT_FUNCTION,
36645  OOMPH_EXCEPTION_LOCATION);
36646  }
36647 #endif
36648 
36649  // Sorted segments (to create a polyline -- boundary)
36650  std::map<unsigned, std::list<unsigned> > sorted_boundary_segments;
36651 
36652  // Go through all the found boundaries
36653  std::map<unsigned,Vector<std::pair<unsigned,unsigned> > >::iterator it;
36654 
36655  for (it = unsorted_boundary_segments.begin();
36656  it != unsorted_boundary_segments.end();
36657  it++)
36658  {
36659  // Get the current boundary id, only look for the segments
36660  // associated with this boundary
36661  const unsigned bnd_id = (*it).first;
36662  Vector<std::pair<unsigned, unsigned> > segments_edges = (*it).second;
36663 
36664  // Now sort the segments associated to this boundary
36665  std::map<std::pair<unsigned, unsigned>, bool> segment_done;
36666  const unsigned nsegments = segments_edges.size();
36667 
36668  // Sorted nodes for the current segment
36669  std::list<unsigned> sorted_segments;
36670 
36671  // Get the left and right node of the zero segment
36672  unsigned left_node_id = segments_edges[0].first;
36673  unsigned right_node_id = segments_edges[0].second;
36674 
36675  // ... and add it to the sorted segments structure
36676  sorted_segments.push_back(left_node_id);
36677  sorted_segments.push_back(right_node_id);
36678 
36679  // Mark the current segment as done
36680  segment_done[segments_edges[0]] = true;
36681 
36682  // Set the number of sorted segments
36683  unsigned nsorted_segments = 1;
36684 
36685  while(nsorted_segments < nsegments)
36686  {
36687  for (unsigned i = 1; i < nsegments; i++)
36688  {
36689  // Check if the i-th segments has been done
36690  if (!segment_done[segments_edges[i]])
36691  {
36692  // Get the left and right node id
36693  unsigned current_left_node_id = segments_edges[i].first;
36694  unsigned current_right_node_id = segments_edges[i].second;
36695 
36696  // Now check if the current segment can be added to the left
36697  // or right side of the sorted segments
36698  if (current_left_node_id == right_node_id)
36699  {
36700  // Add the current_right_node_id to the right of the sorted
36701  // segments
36702  sorted_segments.push_back(current_right_node_id);
36703  // Increase the number of sorted segments
36704  nsorted_segments++;
36705  // Mark the segment as done
36706  segment_done[segments_edges[i]] = true;
36707  // Update the right most node
36708  right_node_id = current_right_node_id;
36709  // Break the for loop
36710  break;
36711  }
36712  else if (current_right_node_id == left_node_id)
36713  {
36714  // Add the current_left_node_id to the left of the sorted
36715  // segments
36716  sorted_segments.push_front(current_left_node_id);
36717  // Increase the number of sorted segments
36718  nsorted_segments++;
36719  // Mark the segment as done
36720  segment_done[segments_edges[i]] = true;
36721  // Update the left most node
36722  left_node_id = current_left_node_id;
36723  // Break the for loop
36724  break;
36725  }
36726  else if (current_left_node_id == left_node_id)
36727  {
36728  // Add the current_right_node_id to the left of the sorted
36729  // segments
36730  sorted_segments.push_front(current_right_node_id);
36731  // Increase the number of sorted segments
36732  nsorted_segments++;
36733  // Mark the segment as done
36734  segment_done[segments_edges[i]] = true;
36735  // Update the left most node
36736  left_node_id = current_right_node_id;
36737  // Break the for loop
36738  break;
36739  }
36740  else if (current_right_node_id == right_node_id)
36741  {
36742  // Add the current_left_node_id to the right of the sorted
36743  // segments
36744  sorted_segments.push_back(current_left_node_id);
36745  // Increase the number of sorted segments
36746  nsorted_segments++;
36747  // Mark the segment as done
36748  segment_done[segments_edges[i]] = true;
36749  // Update the left most node
36750  right_node_id = current_left_node_id;
36751  // Break the for loop
36752  break;
36753  }
36754  } // if (!segment_done[segments_edges[i]])
36755  } // for (i < nsegments)
36756  } // while(nsorted_segments < nsegments)
36757 
36758  sorted_boundary_segments[bnd_id] = sorted_segments;
36759 
36760  } // for (unsorted_boundary_segments.begin();
36761  // unsorted_boundary_segments.end())
36762 
36763 #ifdef PARANOID
36764  if (sorted_boundary_segments.size() != this->nboundary())
36765  {
36766  std::ostringstream error_message;
36767  error_message
36768  << "The number of boundaries on the mesh (" << this->nboundary()
36769  << ") is different from the number\nof sorted boundaries to create the "
36770  << "polylines (" << sorted_boundary_segments.size() << ")\n\n";
36771  throw OomphLibError(error_message.str(),
36772  OOMPH_CURRENT_FUNCTION,
36773  OOMPH_EXCEPTION_LOCATION);
36774  }
36775 #endif
36776 
36777  // Now we have the sorted nodes, we can create the polylines by
36778  // getting the vertices of the nodes
36779  Vector<TriangleMeshPolyLine*> polylines_pt(nboundary);
36780  unsigned current_polyline = 0;
36781 
36782  // Go through the sorted boundaries using the sorted boundaries ids
36783  for (unsigned ib = 0; ib < nsorted_boundaries_ids; ib++)
36784  {
36785  // Get the boundary id from the vector of sorted boundaries ids
36786  const unsigned bnd_id = sorted_boundaries_ids[ib];
36787 
36788  // Create a vector representation for ease to use
36789  // Get the vertices of the nodes that create the boundary / polyline
36790  Vector<unsigned> nodes_ids;
36791  for (std::list<unsigned>::iterator it_list =
36792  sorted_boundary_segments[bnd_id].begin();
36793  it_list != sorted_boundary_segments[bnd_id].end();
36794  it_list++)
36795  {nodes_ids.push_back((*it_list));}
36796 
36797  // Get the number of vertices for the polyline
36798  const unsigned nvertices = nodes_ids.size();
36799 
36800  // The storage for the vertices
36801  Vector<Vector<double> > vertices(nvertices);
36802 
36803  // Now get the vertices of the nodes of the current boundary
36804  for (unsigned i = 0; i < nvertices; i++)
36805  {
36806  // Get the vertices
36807  vertices[i].resize(2);
36808  vertices[i][0] = x_node[nodes_ids[i]-1];
36809  vertices[i][1] = y_node[nodes_ids[i]-1];
36810  }
36811 
36812  // Now create the polyline
36813 
36814  // Note: The bnd_id is the real bnd_id (from the input file) - 1
36815  // since nodes and elements of the current boundary have been
36816  // associated to bnd_id - 1)
36817  polylines_pt[current_polyline] =
36818  new TriangleMeshPolyLine(vertices, bnd_id);
36819 
36820  // Updates bnd_id<--->curve section map
36821  this->Boundary_curve_section_pt[bnd_id] =
36822  dynamic_cast<TriangleMeshCurveSection*>(polylines_pt[current_polyline]);
36823 
36824  // Increase the index for the polyline storage
36825  current_polyline++;
36826 
36827  } // for (it_sorted = sorted_boundary_segments.begin();
36828  // it_sorted != sorted_boundary_segments.end())
36829 
36830  // Now create the polygons or closed curves
36831  // Sort the polylines to create polygons
36832  unsigned nsorted_polylines = 0;
36833 
36834  // Number of created polygons
36835  unsigned npolygons = 0;
36836 
36837  // Storage for the polygons
36838  Vector<TriangleMeshPolygon*> polygons_pt;
36839 
36840  // Mark the already done polylines
36841  std::map<unsigned, bool> polyline_done;
36842  while(nsorted_polylines < nboundary)
36843  {
36844  // Storage for the curve sections that create a polygon
36845  std::list<TriangleMeshCurveSection*> sorted_curve_sections_pt;
36846 
36847  unsigned init_poly = 0;
36848 #ifdef PARANOID
36849  bool found_root_polyline = false;
36850 #endif
36851  // Get the left and right node of the current polyline
36852  for (unsigned i = 0; i < nboundary; i++)
36853  {
36854  if (!polyline_done[i])
36855  {
36856  init_poly = i;
36857  // Increase the number of sorted polylines
36858  nsorted_polylines++;
36859 #ifdef PARANOID
36860  // Mark as found the root polyline
36861  found_root_polyline = true;
36862 #endif
36863  // Mark the polyline as done
36864  polyline_done[i] = true;
36865  // Add the polyline to the curve sections storage
36866  sorted_curve_sections_pt.push_back(polylines_pt[i]);
36867  // Break the loop to set we have found a root polyline
36868  break;
36869  }
36870  }
36871 
36872 #ifdef PARANOID
36873  if (!found_root_polyline)
36874  {
36875  std::ostringstream error_message;
36876  error_message
36877  << "Was not possible to found the root polyline to create polygons\n\n";
36878  throw OomphLibError(error_message.str(),
36879  OOMPH_CURRENT_FUNCTION,
36880  OOMPH_EXCEPTION_LOCATION);
36881  }
36882 #endif
36883 
36884  // Get the associated boundary to the current polyline
36885  const unsigned bnd_id = polylines_pt[init_poly]->boundary_id();
36886  // Get the initial and final node id of the current polyline
36887  unsigned left_node_id = sorted_boundary_segments[bnd_id].front();
36888  unsigned right_node_id = sorted_boundary_segments[bnd_id].back();
36889 
36890  // Flag to know that we already have a closed polygon
36891  bool closed_polygon = false;
36892 
36893  do
36894  {
36895  // Go through all the polylines
36896  for (unsigned i = init_poly; i < nboundary; i++)
36897  {
36898  // Check that the polyline has not been currently done
36899  if (!polyline_done[i])
36900  {
36901  // Get the initial and final nodes id of the current polyline
36902 
36903  // Get the associated boundary to the current polyline
36904  const unsigned cbnd_id = polylines_pt[i]->boundary_id();
36905  // Get the initial and final node id of the current polyline
36906  unsigned cleft_node_id = sorted_boundary_segments[cbnd_id].front();
36907  unsigned cright_node_id = sorted_boundary_segments[cbnd_id].back();
36908 
36909  // Check if the polyline goes to the left or right of the
36910  // current sorted polylines
36911  if (cleft_node_id == right_node_id)
36912  {
36913  // Add the polyline to the curve section storage
36914  sorted_curve_sections_pt.push_back(polylines_pt[i]);
36915  // Mark the polyline as done
36916  polyline_done[i] = true;
36917  // Update the right node
36918  right_node_id = cright_node_id;
36919  // Increase the number of done polyines
36920  nsorted_polylines++;
36921  // Break the for loop
36922  break;
36923  }
36924  else if (cright_node_id == left_node_id)
36925  {
36926  // Add the polyline to the curve section storage
36927  sorted_curve_sections_pt.push_front(polylines_pt[i]);
36928  // Mark the polyline as done
36929  polyline_done[i] = true;
36930  // Update the right node
36931  left_node_id = cleft_node_id;
36932  // Increase the number of done polyines
36933  nsorted_polylines++;
36934  // Break the for loop
36935  break;
36936  }
36937  else if (cleft_node_id == left_node_id)
36938  {
36939  // First reverse the polyline
36940  polylines_pt[i]->reverse();
36941  // Add the polyline to the curve section storage
36942  sorted_curve_sections_pt.push_front(polylines_pt[i]);
36943  // Mark the polyline as done
36944  polyline_done[i] = true;
36945  // Update the right node
36946  left_node_id = cright_node_id;
36947  // Increase the number of done polyines
36948  nsorted_polylines++;
36949  // Break the for loop
36950  break;
36951  }
36952  else if (cright_node_id == right_node_id)
36953  {
36954  // First reverse the polyline
36955  polylines_pt[i]->reverse();
36956  // Add the polyline to the curve section storage
36957  sorted_curve_sections_pt.push_back(polylines_pt[i]);
36958  // Mark the polyline as done
36959  polyline_done[i] = true;
36960  // Update the right node
36961  right_node_id = cleft_node_id;
36962  // Increase the number of done polyines
36963  nsorted_polylines++;
36964  // Break the for loop
36965  break;
36966  }
36967  } // if (!polyline_done[i])
36968 
36969  } // for (i < nboundary)
36970 
36971  // We have created a polygon
36972  if (left_node_id == right_node_id)
36973  {
36974  // Set the flag as true
36975  closed_polygon = true;
36976  }
36977 
36978  }while(nsorted_polylines < nboundary && !closed_polygon);
36979 
36980 #ifdef PARANOID
36981  if (!closed_polygon)
36982  {
36983  std::ostringstream error_message;
36984  error_message
36985  << "It was not possible to create a closed curve, these are the "
36986  << "vertices of the already sorted polylines\n\n";
36987  unsigned cpolyline = 0;
36988  for (std::list<TriangleMeshCurveSection*>::iterator it_list =
36989  sorted_curve_sections_pt.begin();
36990  it_list != sorted_curve_sections_pt.end();
36991  it_list++)
36992  {
36993  error_message << "Polyline (" << cpolyline << ")\n";
36994  TriangleMeshPolyLine *tmp_poly_pt =
36995  dynamic_cast<TriangleMeshPolyLine*>((*it_list));
36996  const unsigned nvertex = tmp_poly_pt->nvertex();
36997  for (unsigned v = 0; v < nvertex; v++)
36998  {
36999  error_message <<"("<<tmp_poly_pt->vertex_coordinate(v)[0]
37000  <<", "<<tmp_poly_pt->vertex_coordinate(v)[1]<<")\n";
37001  }
37002  error_message << "\n";
37003  cpolyline++;
37004  }
37005  throw OomphLibError(error_message.str(),
37006  OOMPH_CURRENT_FUNCTION,
37007  OOMPH_EXCEPTION_LOCATION);
37008  }
37009 #endif
37010 
37011  // Create a vector version to create the polygon from the sorted
37012  // polyines
37013  Vector<TriangleMeshCurveSection*> tmp_sorted_curve_sections_pt;
37014  for (std::list<TriangleMeshCurveSection*>::iterator it_list =
37015  sorted_curve_sections_pt.begin();
37016  it_list != sorted_curve_sections_pt.end();
37017  it_list++)
37018  {tmp_sorted_curve_sections_pt.push_back((*it_list));}
37019 
37020  // Create a new polygon by using the new created polylines
37021  TriangleMeshPolygon *polygon_pt =
37022  new TriangleMeshPolygon(tmp_sorted_curve_sections_pt);
37023 
37024  // Keep track of new created polygons that need to be deleted!!!
37025  this->Free_polygon_pt.insert(polygon_pt);
37026 
37027  // Store the polygon in the polygons storages
37028  polygons_pt.push_back(polygon_pt);
37029 
37030  npolygons++;
37031 
37032  } // while(nsorted_polylines < nboundary)
37033 
37034  // ------------------------------------------------------------------
37035  // Before filling the data structures we need to identify the outer
37036  // closed boundary and the inner closed boundaries.
37037  // If the nodes are not in order we throw a warning message
37038 
37039  // Index for the polygon that is currently considered as the outer
37040  // boundary
37041  unsigned index_outer = 0;
37042 
37043  for (unsigned idx_outer = 0; idx_outer < npolygons; idx_outer++)
37044  {
37045  // Get the vertices of the outer boundary
37046  Vector<Vector<double> > outer_vertex_coordinates;
37047 
37048  // Flag to know if ALL the inner closed boundaries are inside the
37049  // outer closed boundary
37050  bool all_inner_inside = true;
37051 
37052  // Number of polylines of the outer boundary
37053  const unsigned nouter_polylines = polygons_pt[idx_outer]->npolyline();
37054  for (unsigned p = 0; p < nouter_polylines; p++)
37055  {
37056  TriangleMeshPolyLine* tmp_poly_pt =
37057  polygons_pt[idx_outer]->polyline_pt(p);
37058  const unsigned nvertex = tmp_poly_pt->nvertex();
37059  for (unsigned v = 0; v < nvertex; v++)
37060  {
37061  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
37062  outer_vertex_coordinates.push_back(current_vertex);
37063  } // for (v < nvertex)
37064  } // for (p < nouter_polylines)
37065 
37066  // Now get the vertices for the inner boundaries
37067 
37068  // First get the number of inner closed boundaries (polygons size
37069  // minus one because one of the polygons is considered to be the
37070  // outer closed boundary
37071  const unsigned ninner_polygons = polygons_pt.size() - 1;
37072 
37073  // Store the vertices of the inner closed boundaries
37074  Vector<Vector<Vector<double> > > inner_vertex_coordinates(ninner_polygons);
37075  // Get all the vertices of the inner closed boundaries
37076  for (unsigned i = 0; i <= ninner_polygons; i++)
37077  {
37078  if (i != idx_outer)
37079  {
37080  // Number of polylines of the current internal closed boundary
37081  const unsigned ninner_polylines = polygons_pt[i]->npolyline();
37082  for (unsigned p = 0; p < ninner_polylines; p++)
37083  {
37084  TriangleMeshPolyLine* tmp_poly_pt = polygons_pt[i]->polyline_pt(p);
37085  const unsigned nvertex = tmp_poly_pt->nvertex();
37086  for (unsigned v = 0; v < nvertex; v++)
37087  {
37088  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
37089  if (i < idx_outer)
37090  {
37091  inner_vertex_coordinates[i].push_back(current_vertex);
37092  }
37093  else if (i > idx_outer)
37094  {
37095  inner_vertex_coordinates[i-1].push_back(current_vertex);
37096  }
37097  } // for (v < nvertex)
37098 
37099  } // for (p < ninner_polylines)
37100 
37101  } // if (i != index_outer)
37102 
37103  } // for (i <= ninner_polygons)
37104 
37105  // Now check that ALL the vertices of ALL the internal closed
37106  // boundaries are inside the outer closed boundary
37107  for (unsigned i = 0; i < ninner_polygons; i++)
37108  {
37109  // Get the number of vertices in the current internal closed
37110  // boundary
37111  const unsigned nvertex_internal = inner_vertex_coordinates[i].size();
37112  for (unsigned v = 0; v < nvertex_internal; v++)
37113  {
37114  // Get a vertex in the current internal closed boundary
37115  Vector<double> current_point = inner_vertex_coordinates[i][v];
37116  all_inner_inside &=
37117  this->is_point_inside_polygon_helper(outer_vertex_coordinates,
37118  current_point);
37119 
37120  // Check if we should continue checking for more points inside
37121  // the current proposed outer boundary
37122  if (!all_inner_inside)
37123  {
37124  // Break the "for" for the vertices
37125  break;
37126  }
37127 
37128  } // for (v < nvertex_internal)
37129 
37130  // Check if we should continue checking for more inner closed
37131  // boundaries inside the current proposed outer boundary
37132  if (!all_inner_inside)
37133  {
37134  // Break the "for" for the inner boundaries
37135  break;
37136  }
37137 
37138  } // for (i < ninner_polygons)
37139 
37140  // Check if all the vertices of all the polygones are inside the
37141  // current proposed outer boundary
37142  if (all_inner_inside)
37143  {
37144  index_outer = idx_outer;
37145  break;
37146  }
37147 
37148  } // for (idx_outer < npolygons)
37149 
37150 #ifdef PARANOID
37151  // Check if the first nodes listed in the polyfiles correspond to
37152  // the outer boundary, if that is not the case then throw a warning
37153  // message
37154  if (index_outer != 0)
37155  {
37156  std::ostringstream warning_message;
37157  warning_message
37158  << "The first set of nodes listed in the input polyfiles does not\n"
37159  << "correspond to the outer closed boundary. This may lead to\n"
37160  << "problems at the adaptation stage if the holes coordinates\n"
37161  << "are no correctly associated to the inner closed boundaries.\n"
37162  << "You can check the generated mesh by calling the output() method\n"
37163  << "from the mesh object '(problem.mesh_pt()->output(string))'\n\n";
37164  OomphLibWarning(warning_message.str(),
37165  OOMPH_CURRENT_FUNCTION,
37166  OOMPH_EXCEPTION_LOCATION);
37167  } // if (index_outer != 0)
37168 #endif
37169 
37170  // ------------------------------------------------------------------
37171  // Now fill the data structures
37172 
37173  // Store outer polygon
37174  // We are assuming there is only one outer polygon
37175  this->Outer_boundary_pt.resize(1);
37176  this->Outer_boundary_pt[0] = polygons_pt[index_outer];
37177 
37178  this->Internal_polygon_pt.resize(npolygons-1);
37179  for (unsigned i = 0; i < npolygons; i++)
37180  {
37181  if (i != index_outer)
37182  {
37183  if (i < index_outer)
37184  {
37185  // Store internal polygons by copy constructor
37186  this->Internal_polygon_pt[i] = polygons_pt[i];
37187  }
37188  else if (i > index_outer)
37189  {
37190  // Store internal polygons by copy constructor
37191  this->Internal_polygon_pt[i-1] = polygons_pt[i];
37192  }
37193  } // if (i != index_outer)
37194  } // for (i < npolygons)
37195 
37196  // Before assigning the hole vertex coordinate to the inner closed
37197  // boundaries check that the holes are listed in orderm if that is
37198  // not the case the associate each hole vertex coordinate to the
37199  // inner closed boundaries
37200 
37201  // Store the vertices of the inner closed boundaries
37202  Vector<Vector<Vector<double> > > inner_vertex_coordinates(npolygons-1);
37203  // Get all the vertices of the inner closed boundaries
37204  for (unsigned i = 0; i < npolygons-1; i++)
37205  {
37206  // Number of polylines of the current internal closed boundary
37207  const unsigned ninner_polylines =
37208  this->Internal_polygon_pt[i]->npolyline();
37209  for (unsigned p = 0; p < ninner_polylines; p++)
37210  {
37211  TriangleMeshPolyLine* tmp_poly_pt =
37212  this->Internal_polygon_pt[i]->polyline_pt(p);
37213  // Number of vertices of the current polyline in the current
37214  // internal closed polygon
37215  const unsigned nvertex = tmp_poly_pt->nvertex();
37216  for (unsigned v = 0; v < nvertex; v++)
37217  {
37218  Vector<double> current_vertex = tmp_poly_pt->vertex_coordinate(v);
37219  inner_vertex_coordinates[i].push_back(current_vertex);
37220  } // for (v < nvertex)
37221 
37222  } // for (p < ninner_polylines)
37223 
37224  } // for (i <= ninner_polygons)
37225 
37226  // Holes information
37227  unsigned nholes;
37228  poly_file >> nholes;
37229 
37230 #ifdef PARANOID
37231  if (npolygons > 1 && (npolygons - 1) != nholes)
37232  {
37233  std::ostringstream error_message;
37234  error_message
37235  << "The number of holes (" << nholes << ") does not correspond "
37236  << "with the number\nof internal polygons ("
37237  << npolygons - 1 <<")\n\n"
37238  << "Using polyfiles as input does not currently allows the\n"
37239  << "definition of more than one outer polygon\n\n";
37240  throw OomphLibError(error_message.str(),
37241  OOMPH_CURRENT_FUNCTION,
37242  OOMPH_EXCEPTION_LOCATION);
37243  }
37244 #endif
37245 
37246  // Storage for the holes
37247  Vector<Vector<double> > hole_coordinates(nholes);
37248 
37249  // Dummy for hole number
37250  unsigned dummy_hole;
37251  // Loop over the holes to get centre coords
37252  for(unsigned ihole=0;ihole<nholes;ihole++)
37253  {
37254  hole_coordinates[ihole].resize(2);
37255  // Read the centre value
37256  poly_file >> dummy_hole;
37257  poly_file >> hole_coordinates[ihole][0];
37258  poly_file >> hole_coordinates[ihole][1];
37259  }
37260 
37261  // Vector that store the index of the hole coordinate that
37262  // correspond to each internal closed polygon
37263  Vector<unsigned> index_hole_of_internal_polygon(npolygons-1);
37264  std::map<unsigned, bool> hole_done;
37265 
37266  // Now associate each hole vertex to a corresponding internal closed
37267  // polygon
37268  for (unsigned i = 0; i < npolygons-1; i++)
37269  {
37270  // Find which hole is associated to each internal closed boundary
37271  for (unsigned h = 0; h < nholes; h++)
37272  {
37273  // If the hole has not been previously associated
37274  if (!hole_done[h])
37275  {
37276  // Get the hole coordinate
37277  Vector<double> current_point = hole_coordinates[h];
37278 
37279  const bool hole_in_polygon =
37280  this->is_point_inside_polygon_helper(inner_vertex_coordinates[i],
37281  current_point);
37282 
37283  // If the hole is inside the polygon
37284  if (hole_in_polygon)
37285  {
37286  // Mark the hole as done
37287  hole_done[h] = true;
37288  // Associate the current hole with the current inner closed
37289  // boundary
37290  index_hole_of_internal_polygon[i] = h;
37291  // Break the search
37292  break;
37293  }
37294 
37295  } // if (!hole_done[h])
37296 
37297  } // for (h < nholes)
37298 
37299  } // for (i < npolygons-1)
37300 
37301 #ifdef PARANOID
37302  if (hole_done.size() != npolygons-1)
37303  {
37304  std::ostringstream error_message;
37305  error_message
37306  << "Not all the holes were associated to an internal closed boundary\n"
37307  << "Only ("<<hole_done.size()<<") holes were assigned for a total of\n"
37308  << "(" << npolygons-1 << ") internal closed boundaries.\n"
37309  << "You can check the generated mesh by calling the output() method\n"
37310  << "from the mesh object '(problem.mesh_pt()->output(string))'\n\n";
37311  throw OomphLibError(error_message.str(),
37312  OOMPH_CURRENT_FUNCTION,
37313  OOMPH_EXCEPTION_LOCATION);
37314  } // if (index_hole != ihole)
37315 #endif
37316 
37317  // Assign the holes coordinates to the internal polygons
37318  for (unsigned ihole = 0; ihole < nholes; ihole++)
37319  {
37320  // Get the index hole of the current internal closed polygon
37321  const unsigned index_hole = index_hole_of_internal_polygon[ihole];
37322 #ifdef PARANOID
37323  // Check if the hole index is the same as the internal closed
37324  // boundary, it means that the holes were listed in the same order
37325  // as the nodes of the internal closed boundaries
37326  if (index_hole != ihole)
37327  {
37328  std::ostringstream error_message;
37329  error_message
37330  << "The hole vertices coordinates are not listed in the same order\n"
37331  << "as the nodes that define the internal closed boundaries.\n"
37332  << "This may lead to problems in case that the holes coordinates\n"
37333  << "were no properly assigned to the internal closed boundaries.\n"
37334  << "You can check the generated mesh by calling the output() method\n"
37335  << "from the mesh object '(problem.mesh_pt()->output(string))'\n\n";
37336  throw OomphLibError(error_message.str(),
37337  OOMPH_CURRENT_FUNCTION,
37338  OOMPH_EXCEPTION_LOCATION);
37339  } // if (index_hole != ihole)
37340 #endif
37341 
37342  // Set the hole coordinate for the internal polygon
37343  this->Internal_polygon_pt[ihole]->internal_point() =
37344  hole_coordinates[index_hole];
37345  }
37346 
37347  // Ignore the first line with structure description
37348  poly_file.ignore(80,'\n');
37349 
37350  // Regions information
37351  unsigned nregions;
37352 
37353  // Extract regions information
37354  // But first check if there are regions or not
37355  std::string regions_info_string;
37356 
37357  // Read line up to termination sign
37358  getline(poly_file, regions_info_string);
37359 
37360  // Check if the read string is a number or a comment wrote by triangle,
37361  // if it is a number then that is the number of regions
37362  if (isdigit(regions_info_string.c_str()[0]))
37363  {
37364  nregions = std::atoi(regions_info_string.c_str());
37365  }
37366  else
37367  {
37368  nregions = 0;
37369  }
37370 
37371  // The regions coordinates
37372  std::map<unsigned, Vector<double> > regions_coordinates;
37373 
37374  // Dummy for regions number
37375  unsigned dummy_region;
37376 
37377  unsigned region_id;
37378 
37379  // Loop over the regions to get their coords
37380  for(unsigned iregion=0;iregion<nregions;iregion++)
37381  {
37382  Vector<double> tmp_region_coordinates(2);
37383  // Read the regions coordinates
37384  poly_file >> dummy_region;
37385  poly_file >> tmp_region_coordinates[0];
37386  poly_file >> tmp_region_coordinates[1];
37387  poly_file >> region_id;
37388  regions_coordinates[region_id].resize(2);
37389  regions_coordinates[region_id][0] = tmp_region_coordinates[0];
37390  regions_coordinates[region_id][1] = tmp_region_coordinates[1];
37391 
37392  // Ignore the first line with structure description
37393  poly_file.ignore(80,'\n');
37394 
37395  // Verify if not using the default region number (zero)
37396  if (region_id == 0)
37397  {
37398  std::ostringstream error_message;
37399  error_message << "Please use another region id different from zero.\n"
37400  << "It is internally used as the default region number.\n";
37401  throw OomphLibError(error_message.str(),
37402  OOMPH_CURRENT_FUNCTION,
37403  OOMPH_EXCEPTION_LOCATION);
37404  }
37405 
37406  }
37407 
37408  // Store the extra regions coordinates
37409  this->Regions_coordinates = regions_coordinates;
37410 
37411  poly_file.close();
37412 
37413  }
37414 
37415 //======================================================================
37416 /// \short Updates the polygon but using the elements area instead of
37417 /// the default refinement and unrefinement methods
37418 //======================================================================
37419 template <class ELEMENT>
37421 update_polygon_using_elements_area(TriangleMeshPolygon* &polygon_pt,
37422  const Vector<double> &target_area)
37423 {
37424  // Verify that there was a change on the polygon representation
37425  unsigned update_was_performed = false;
37426 
37427  const unsigned nele = this->nelement();
37428 
37429  // - Get the vertices along the boundaries and for each element identify
37430  // its associated target error.
37431  // - Get face mesh representation of each polyline.
37432  // - Get the vertices with the help of face elements.
37433  // - Find the global index in the mesh of the face element and use
37434  // it to get its associated target area
37435 
37436  // Get the face mesh representation
37437  Vector<Mesh*> face_mesh_pt;
37438  get_face_mesh_representation(polygon_pt,face_mesh_pt);
37439 
37440  // Create vertices of the polylines by using the vertices of the
37441  // FaceElements
37442  Vector<double> vertex_coord(3); // zeta,x,y
37443  Vector<double> bound_left(1);
37444  Vector<double> bound_right(1);
37445 
37446  unsigned n_polyline = polygon_pt->npolyline();
37447 
37448  // Go for each polyline
37449  for(unsigned p = 0; p < n_polyline; p++)
37450  {
37451  // Get the MeshAsGeomObject representation just once per polyline,
37452  // this object is only used by the
37453  // refine_boundary_constrained_by_target_area() method. We get it
37454  // here to ensure that all processors (in a distributed context)
37455  // get this representation just once, and because an AllToAll MPI
37456  // communication is used in this calling
37457  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt[p]);
37458 
37459  // Set of coordinates on the boundary
37460  // Set entries are ordered on first entry in vector which stores
37461  // the boundary coordinate so the vertices come out in order!
37462  std::set<Vector<double> > vertex_nodes;
37463 
37464  // Vector to store the vertices, transfer the sorted vertices from the
37465  // set to this vector, --- including the z-value ---
37466  Vector<Vector<double> > tmp_vector_vertex_node;
37467 
37468  // Vector to store the coordinates of the polylines, same as the
37469  // tmp_vector_vertex_node vector (after adding more nodes) but
37470  // --- without the z-value ---, used to re-generate the polylines
37471  Vector<Vector<double> > vector_vertex_node;
37472 
37473 #ifdef OOMPH_HAS_MPI
37474  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
37475  // Set of coordinates that are on the boundary (splitted boundary version)
37476  // The first vector is used to allocate the points for each sub-boundary
37477  // Set entries are ordered on first entry in vector which stores
37478  // the boundary coordinate so the vertices come out in order!
37479  Vector<std::set<Vector<double> > >sub_vertex_nodes;
37480 
37481  // Vector to store the vertices, transfer the sorted vertices from the
37482  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
37483  Vector<Vector<Vector<double> > >sub_tmp_vector_vertex_node;
37484 
37485  // Vector to store the coordinates of the polylines that will represent
37486  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
37487  // but --- without the z-value ---, used to generate the sub-polylines
37488  Vector<Vector<Vector<double> > > sub_vector_vertex_node;
37489  // --------- Stuff to deal with splitted boundaries ----------- End ------
37490 #endif
37491 
37492  //Get the boundary id
37493  const unsigned bound = polygon_pt->curve_section_pt(p)->boundary_id();
37494 
37495  // Get the chunk number
37496  const unsigned chunk = polygon_pt->curve_section_pt(p)->boundary_chunk();
37497 
37498  /// Use a vector of vector for vertices and target areas to deal
37499  /// with the cases when the boundaries are split by the
37500  /// distribution process
37501 
37502  // Loop over the face elements (ordered) and add their vertices
37503  const unsigned nface_element = face_mesh_pt[p]->nelement();
37504 
37505  // Store the non halo face elements, the ones from which we will
37506  // get the vertices
37507  Vector<FiniteElement*> non_halo_face_element_pt;
37508 
37509  // Map to store the index of the face element on a boundary
37510  std::map<FiniteElement*,unsigned> face_element_index_on_boundary;
37511 
37512  for(unsigned ef=0;ef<nface_element;++ef)
37513  {
37514  FiniteElement* ele_face_pt = face_mesh_pt[p]->finite_element_pt(ef);
37515 #ifdef OOMPH_HAS_MPI
37516  // Skip the halo elements if working with a distributed mesh
37517  if (this->is_mesh_distributed() && ele_face_pt->is_halo())
37518  {continue;}
37519 #endif
37520  // Add the face element to the vector
37521  non_halo_face_element_pt.push_back(ele_face_pt);
37522  face_element_index_on_boundary[ele_face_pt] = ef;
37523  }
37524 
37525  // Get the number of non halo face element
37526  const unsigned nnon_halo_face_element = non_halo_face_element_pt.size();
37527 
37528  // Map to know the already sorted face elements
37529  std::map<FiniteElement*,bool> face_element_done;
37530 
37531  // Number of done face elements
37532  unsigned nsorted_face_elements = 0;
37533 
37534 #ifdef OOMPH_HAS_MPI
37535  // Counter for sub_boundaries
37536  unsigned nsub_boundaries = 0;
37537 #endif // #ifdef OOMPH_HAS_MPI
37538 
37539  // Continue until all the face elements have been sorted
37540  // While to deal with split boundaries cases
37541  while(nsorted_face_elements < nnon_halo_face_element)
37542  {
37543  // Get and initial face element
37544  FiniteElement* ele_face_pt = 0;
37545 #ifdef PARANOID
37546  bool found_initial_face_element = false;
37547 #endif
37548 
37549  unsigned iface = 0;
37550  for (iface = 0; iface < nnon_halo_face_element; iface++)
37551  {
37552  ele_face_pt = non_halo_face_element_pt[iface];
37553  // If not done then take it as initial face element
37554  if (!face_element_done[ele_face_pt])
37555  {
37556 #ifdef PARANOID
37557  found_initial_face_element = true;
37558 #endif
37559  nsorted_face_elements++;
37560  iface++;
37561  break;
37562  }
37563  }
37564 
37565 #ifdef PARANOID
37566  if (!found_initial_face_element)
37567  {
37568  std::ostringstream error_message;
37569  error_message
37570  <<"Could not find an initial face element for the current segment\n";
37571  // << "----- Possible memory leak -----\n";
37572  throw OomphLibError(error_message.str(),
37573  "RefineableTriangleMesh::update_polygon_using_elements_area()",
37574  OOMPH_EXCEPTION_LOCATION);
37575  }
37576 #endif
37577 
37578  // Local set of coordinates that are on the boundary
37579  // Set entries are ordered on first entry in vector which stores
37580  // the boundary coordinate so the vertices come out in order!
37581  std::set<Vector<double> > local_vertex_nodes;
37582 
37583  // Vector to store the vertices, transfer the sorted vertices from the
37584  // set (local) to this vector (local), --- including the z-value ---
37585  Vector<Vector<double> > local_tmp_vector_vertex_node;
37586 
37587  // Vector to store the target areas, uses the same approach as the
37588  // set for the local_vertex_nodes, ordered on first entry
37589  std::set<Vector<double> > sorted_target_areas;
37590 
37591  // Vector to store the target areas, used to transfer the sorted target
37592  // areas from "local_sorted_target_areas" set
37593  Vector<double> tmp_sorted_target_areas;
37594 
37595  // -----------------------------------------------------------------
37596  // Add the vertices of the initial face element to the set of
37597  // local sorted vertices
37598  // -----------------------------------------------------------------
37599  unsigned nnode = ele_face_pt->nnode();
37600  // Add the left-hand node to the set:
37601  // Boundary coordinate
37602  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound,bound_left);
37603  vertex_coord[0] = bound_left[0];
37604 
37605  // Actual coordinates
37606  for(unsigned i=0;i<2;i++)
37607  {
37608  vertex_coord[i+1] = ele_face_pt->node_pt(0)->x(i);
37609  }
37610  local_vertex_nodes.insert(vertex_coord);
37611 
37612  // Add the right-hand nodes to the set:
37613  // Boundary coordinate
37614  ele_face_pt->node_pt(nnode-1)->
37615  get_coordinates_on_boundary(bound,bound_right);
37616  vertex_coord[0] = bound_right[0];
37617 
37618  // Actual coordinates
37619  for(unsigned i=0;i<2;i++)
37620  {
37621  vertex_coord[i+1] = ele_face_pt->node_pt(nnode-1)->x(i);
37622  }
37623  local_vertex_nodes.insert(vertex_coord);
37624 
37625  // The initial and final node on the set
37626  Node *first_node_pt = ele_face_pt->node_pt(0);
37627  Node *last_node_pt = ele_face_pt->node_pt(nnode-1);
37628 
37629  // Mark the current face element as done
37630  face_element_done[ele_face_pt] = true;
37631 
37632  // -------------------------------------------------------
37633  // Find the global index in the mesh of the face element
37634  // and use it to get its associated target area
37635  // -------------------------------------------------------
37636  // Container to store the zeta value (used as index) and
37637  // the associated target area of the element
37638  Vector<double> zeta_target_area_values(2);
37639 
37640  // Use the minimum zeta value to sort the target areas
37641  // along the boundary
37642  zeta_target_area_values[0] =
37643  std::min(bound_left[0], bound_right[0]);
37644 
37645  // Get the index of the face element on the current boundary
37646  unsigned ef = face_element_index_on_boundary[ele_face_pt];
37647  // Get the "ef"-th element on the boundary
37648  FiniteElement *el_pt = this->boundary_element_pt(bound, ef);
37649 
37650 #ifdef PARANOID
37651  bool found_global_element_index = false;
37652 #endif
37653  for (unsigned eg = 0 ; eg < nele; eg++)
37654  {
37655  // Get the "eg-th" element
37656  FiniteElement *el_compare_pt = this->finite_element_pt(eg);
37657 
37658  // Compare with the element on the boundary, if equal then
37659  // store the target area
37660  if (el_pt == el_compare_pt)
37661  {
37662  zeta_target_area_values[1] = target_area[eg];
37663 #ifdef PARANOID
37664  found_global_element_index = true;
37665 #endif
37666  break; // break the for (e < nele) global element
37667  } // if element_pt == element_compare_pt
37668  } // for nele (on complete mesh)
37669 
37670 #ifdef PARANOID
37671  if (!found_global_element_index)
37672  {
37673  std::ostringstream error_message;
37674  error_message
37675  << "The global index for the ("<< ef <<")-th face element "
37676  << "on\nthe ("<< bound <<")-th boundary was not found!!!";
37677  throw OomphLibError(error_message.str(),
37678  "RefineableTriangleMesh::update_polygon_using_elements_area()",
37679  OOMPH_EXCEPTION_LOCATION);
37680  }
37681 #endif
37682 
37683  // Add the target areas to the sorted set
37684  sorted_target_areas.insert(zeta_target_area_values);
37685  // ------------------------------------------------------------------
37686 
37687  // Continue iterating if a new face element has been added to the
37688  // list
37689  bool face_element_added = false;
37690 
37691  // While a new face element has been added to the set of sorted
37692  // face elements then re-iterate
37693  do
37694  {
37695  // Start from the next face elements since we have already
37696  // added the previous one as the initial face element (any
37697  // previous face element had to be added on previous
37698  // iterations)
37699  for (unsigned iiface=iface;iiface<nnon_halo_face_element;iiface++)
37700  {
37701  face_element_added = false;
37702  ele_face_pt = non_halo_face_element_pt[iiface];
37703  if (!face_element_done[ele_face_pt])
37704  {
37705  // Get each individual node to check if they are contiguous
37706  nnode = ele_face_pt->nnode();
37707  Node* left_node_pt = ele_face_pt->node_pt(0);
37708  Node* right_node_pt = ele_face_pt->node_pt(nnode-1);
37709 
37710  if (left_node_pt == first_node_pt)
37711  {
37712  first_node_pt = right_node_pt;
37713  face_element_added = true;
37714  }
37715  else if (left_node_pt == last_node_pt)
37716  {
37717  last_node_pt = right_node_pt;
37718  face_element_added = true;
37719  }
37720  else if (right_node_pt == first_node_pt)
37721  {
37722  first_node_pt = left_node_pt;
37723  face_element_added = true;
37724  }
37725  else if (right_node_pt == last_node_pt)
37726  {
37727  last_node_pt = left_node_pt;
37728  face_element_added = true;
37729  }
37730 
37731  if (face_element_added)
37732  {
37733  // Add the left-hand node to the set:
37734  // Boundary coordinate
37735  left_node_pt->get_coordinates_on_boundary(bound,bound_left);
37736  vertex_coord[0] = bound_left[0];
37737 
37738  // Actual coordinates
37739  for(unsigned i=0;i<2;i++)
37740  {
37741  vertex_coord[i+1] = left_node_pt->x(i);
37742  }
37743  local_vertex_nodes.insert(vertex_coord);
37744 
37745  // Add the right-hand nodes to the set:
37746  // Boundary coordinate
37747  right_node_pt->get_coordinates_on_boundary(bound,bound_right);
37748  vertex_coord[0] = bound_right[0];
37749 
37750  // Actual coordinates
37751  for(unsigned i=0;i<2;i++)
37752  {
37753  vertex_coord[i+1] = right_node_pt->x(i);
37754  }
37755  local_vertex_nodes.insert(vertex_coord);
37756 
37757  // Mark as done only if one of its nodes has been
37758  // added to the list
37759  face_element_done[ele_face_pt] = true;
37760  nsorted_face_elements++;
37761 
37762  // -----------------------------------------------------
37763  // Find the global index in the mesh of the face element
37764  // and use it to get its associated target area
37765  // -----------------------------------------------------
37766  // Use the minimum zeta value to sort the target areas
37767  // along the boundary
37768  zeta_target_area_values[0] =
37769  std::min(bound_left[0], bound_right[0]);
37770 
37771  // Get the "ef"-th element on the boundary
37772  ef = face_element_index_on_boundary[ele_face_pt];
37773  FiniteElement *lel_pt = this->boundary_element_pt(bound, ef);
37774 
37775 #ifdef PARANOID
37776  found_global_element_index = false;
37777 #endif
37778  for (unsigned eg = 0 ; eg < nele; eg++)
37779  {
37780  // Get the "eg-th" element
37781  FiniteElement *lel_compare_pt = this->finite_element_pt(eg);
37782 
37783  // Compare with the element on the boundary, if equal then
37784  // store the target area
37785  if (lel_pt == lel_compare_pt)
37786  {
37787  zeta_target_area_values[1] = target_area[eg];
37788 #ifdef PARANOID
37789  found_global_element_index = true;
37790 #endif
37791  break; // break the for (e < nele) global element
37792  } // if element_pt == element_compare_pt
37793  } // for nele (on complete mesh)
37794 
37795 #ifdef PARANOID
37796  if (!found_global_element_index)
37797  {
37798  std::ostringstream error_message;
37799  error_message
37800  << "The global index for the ("<< ef <<")-th face element "
37801  << "on\nthe ("<< bound <<")-th boundary was not found!!!";
37802  throw OomphLibError(error_message.str(),
37803  "RefineableTriangleMesh::update_polygon_using_elements_area()",
37804  OOMPH_EXCEPTION_LOCATION);
37805  }
37806 #endif
37807 
37808  // Add the target areas to the sorted set
37809  sorted_target_areas.insert(zeta_target_area_values);
37810 
37811  break;
37812  }
37813 
37814  } // if (!edge_done[edge])
37815  } // for (iiedge < nedges)
37816  }while(face_element_added &&
37817  (nsorted_face_elements < nnon_halo_face_element));
37818 
37819  // -----------------------------------------------------------------
37820  // At this point we already have a sorted set of nodes and
37821  // can be used to peform the unrefinement and refinement procedures
37822  // -----------------------------------------------------------------
37823 
37824  // Get the number of nodes on the list
37825  const unsigned nlocal_nodes = local_vertex_nodes.size();
37826  // Change representation to vector for easy of handling ...
37827  local_tmp_vector_vertex_node.resize(nlocal_nodes);
37828 
37829  // Copy the vertices of the nodes
37830  unsigned counter = 0;
37831  std::set<Vector<double> >::iterator it_vertex;
37832  for (it_vertex = local_vertex_nodes.begin();
37833  it_vertex != local_vertex_nodes.end();
37834  it_vertex++)
37835  {
37836  local_tmp_vector_vertex_node[counter].resize(3);
37837  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
37838  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
37839  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
37840  counter++;
37841  }
37842 
37843  // ... same for the info. related with the target areas (turn
37844  // into vector)
37845  const unsigned ntarget_areas = sorted_target_areas.size();
37846  tmp_sorted_target_areas.resize(ntarget_areas);
37847  counter = 0;
37848  std::set<Vector<double> >::iterator it_area;
37849  for(it_area = sorted_target_areas.begin();
37850  it_area != sorted_target_areas.end();
37851  ++it_area)
37852  {
37853  tmp_sorted_target_areas[counter] = (*it_area)[1];
37854  ++counter;
37855  }
37856 
37857 #ifdef PARANOID
37858  if (nlocal_nodes > 0 && (ntarget_areas != nlocal_nodes - 1) )
37859  {
37860  std::ostringstream error_message;
37861  error_message
37862  << "The boundary (" << bound << ") was split during the "
37863  << "distribution process.\n"
37864  << "The problem is in the association of the target areas with the\n"
37865  << "elements that gave rise to the vertex coordinates.\n"
37866  << "The number of local nodes (" << nlocal_nodes
37867  << "), on the 'sub-polyline', is not\n"
37868  << "according with the number of target "
37869  << "areas ("<< ntarget_areas << ")\nfor that number of nodes.\n"
37870  << "The target areas number MUST be equal to the number of\n"
37871  << "local nodes minus one\n\n";
37872  throw OomphLibError(error_message.str(),
37873  OOMPH_CURRENT_FUNCTION,
37874  OOMPH_EXCEPTION_LOCATION);
37875  }
37876 #endif
37877 
37878  // -------------------------------------------------------------------
37879  // Update the vertices along the boundary using the target area
37880  // to define the distance among them
37881  // -------------------------------------------------------------------
37882 
37883  // Tolerance below which the middle point can be deleted
37884  // (ratio of deflection to element length)
37885  double unrefinement_tolerance=
37886  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
37887 
37888  // Apply unrefinement
37889  bool unrefinement_applied =
37890  unrefine_boundary_constrained_by_target_area(
37891  bound, chunk, local_tmp_vector_vertex_node,
37892  unrefinement_tolerance, tmp_sorted_target_areas);
37893 
37894  // Tolerance for refinement
37895  double refinement_tolerance=
37896  polygon_pt->polyline_pt(p)->refinement_tolerance();
37897 
37898  // Apply refinement
37899  bool refinement_applied =
37900  refine_boundary_constrained_by_target_area(
37901  mesh_geom_obj_pt, local_tmp_vector_vertex_node,
37902  refinement_tolerance, tmp_sorted_target_areas);
37903 
37904  // Clear the local containter to recover the nodes ordered using the
37905  // zeta value
37906  local_vertex_nodes.clear();
37907 
37908  // At the end of each unrefinement/refinement step store the new nodes
37909  // on the set that will give rise to the vertices of the new polyline
37910  // representation
37911  unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
37912  for (unsigned i = 0; i < nnew_nodes; i++)
37913  {
37914  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
37915  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
37916  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
37917  vertex_nodes.insert(vertex_coord); // Global container
37918  local_vertex_nodes.insert(vertex_coord);
37919  }
37920 
37921  // Update the flag to indicate whether an unrefinement or
37922  // refinement was applied
37923  update_was_performed = (unrefinement_applied || refinement_applied);
37924 
37925 #ifdef OOMPH_HAS_MPI
37926  if (this->is_mesh_distributed())
37927  {
37928  // Add the set of vertices for the boundary, this will help to
37929  // detect if we need to deal with sub-boundaries
37930  sub_vertex_nodes.push_back(local_vertex_nodes);
37931  // Increase the counter for sub-boundaries
37932  nsub_boundaries++;
37933  }
37934 #endif
37935 
37936  } // while(nsorted_face_elements < nnon_halo_face_element)
37937 
37938  // Now turn into vector for ease of handling...
37939  unsigned npoly_vertex = vertex_nodes.size();
37940  // This will store all the vertices whether the boundary was split
37941  // or not
37942  tmp_vector_vertex_node.resize(npoly_vertex);
37943  unsigned count = 0;
37944  for(std::set<Vector<double> >::iterator it = vertex_nodes.begin();
37945  it!=vertex_nodes.end(); ++it)
37946  {
37947  tmp_vector_vertex_node[count].resize(3);
37948  tmp_vector_vertex_node[count][0] = (*it)[0];
37949  tmp_vector_vertex_node[count][1] = (*it)[1];
37950  tmp_vector_vertex_node[count][2] = (*it)[2];
37951  ++count;
37952  }
37953 
37954 #ifdef OOMPH_HAS_MPI
37955  // --------- Stuff for the sub_boundaries ----- Begin section ---------
37956 #ifdef PARANOID
37957  unsigned nsub_boundaries_set = sub_vertex_nodes.size();
37958  if (nsub_boundaries_set != nsub_boundaries)
37959  {
37960  std::ostringstream error_message;
37961  error_message
37962  << "The number of found sub-boundaries and the number of counted\n"
37963  << "sub-boundaries are different:\n"
37964  << "Number of found sub-boundaries: ("<<nsub_boundaries_set<<")\n"
37965  << "Number of counted sub-boundaries: ("<<nsub_boundaries<<")\n";
37966  throw OomphLibError(error_message.str(),
37967  OOMPH_CURRENT_FUNCTION,
37968  OOMPH_EXCEPTION_LOCATION);
37969  }
37970 #endif
37971 
37972  // Are there sub-boundaries (only appear in distributed meshes)
37973  if (this->is_mesh_distributed() && nsub_boundaries > 1)
37974  {
37975  // Mark the boundary as been splitted in the partition process
37976  this->Boundary_was_splitted[bound] = true;
37977  // Resize the vector to store the info. of sub-boundaries
37978  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
37979  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
37980  {
37981  // Turn info. into vector for ease of handling...
37982  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
37983  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
37984  unsigned subcount = 0;
37985  std::set<Vector<double> >::iterator subit;
37986  for(subit = sub_vertex_nodes[isub].begin();
37987  subit != sub_vertex_nodes[isub].end(); ++subit)
37988  {
37989  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
37990  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
37991  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
37992  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
37993  ++subcount;
37994  }
37995  }
37996  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
37997  // --------- Stuff for the sub_boundaries ----- End section ------------
37998 #endif // OOMPH_HAS_MPI
37999 
38000  // For further processing the three-dimensional vector has to be
38001  // reduced to a two-dimensional vector
38002  unsigned n_vertex=tmp_vector_vertex_node.size();
38003 
38004  // Resize the vector for vectices
38005  vector_vertex_node.resize(n_vertex);
38006  for(unsigned i=0;i<n_vertex;i++)
38007  {
38008  vector_vertex_node[i].resize(2);
38009  vector_vertex_node[i][0]=tmp_vector_vertex_node[i][1];
38010  vector_vertex_node[i][1]=tmp_vector_vertex_node[i][2];
38011  }
38012 
38013 #ifdef OOMPH_HAS_MPI
38014  // --------- Stuff for the sub_boundaries ----- Begin section ----------
38015  // Verify if need to deal with sub_boundaries
38016  if (this->is_mesh_distributed() && nsub_boundaries > 1)
38017  {
38018  // For further processing the three-dimensional vector
38019  // has to be reduced to a two-dimensional vector
38020  // Resize the vector to store the info. of sub-boundaries
38021  sub_vector_vertex_node.resize(nsub_boundaries);
38022  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
38023  {
38024  const unsigned subn_vertex =
38025  sub_tmp_vector_vertex_node[isub].size();
38026  // Resize the vector for vectices
38027  sub_vector_vertex_node[isub].resize(subn_vertex);
38028  for(unsigned i=0;i<subn_vertex;i++)
38029  {
38030  sub_vector_vertex_node[isub][i].resize(2);
38031  sub_vector_vertex_node[isub][i][0]=
38032  sub_tmp_vector_vertex_node[isub][i][1];
38033  sub_vector_vertex_node[isub][i][1]=
38034  sub_tmp_vector_vertex_node[isub][i][2];
38035  }
38036  }
38037  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
38038 
38039  // We already have the info. for the sub-boundaries (if necessary)
38040  // and then we can create the sub-boundaries representations to
38041  // ease the generation of the mesh by Triangle
38042 
38043  // --------- Stuff for the sub_boundaries ----- End section ------------
38044  #endif // OOMPH_HAS_MPI
38045 
38046  // --------------------------------------------------------------------
38047  // Check for contiguousness
38048  // --------------------------------------------------------------------
38049 #ifdef OOMPH_HAS_MPI
38050  // Only perform this checking if the mesh is not distributed. When
38051  // the mesh is distributed the polylines continuity is addressed
38052  // by the sort_polylines_helper() method
38053  if (!this->is_mesh_distributed())
38054 #endif
38055  {
38056  if ( p > 0 )
38057  {
38058  //Final end point of previous line
38059  Vector<double> final_vertex_of_previous_segment;
38060  unsigned n_prev_vertex =
38061  polygon_pt->curve_section_pt(p-1)->nvertex();
38062  final_vertex_of_previous_segment =
38063  polygon_pt->polyline_pt(p-1)->
38064  vertex_coordinate(n_prev_vertex-1);
38065 
38066  unsigned prev_seg_boundary_id =
38067  polygon_pt->curve_section_pt(p-1)->boundary_id();
38068 
38069  //Find the error between the final vertex of the previous
38070  //line and the first vertex of the current line
38071  double error = 0.0;
38072  for(unsigned i=0;i<2;i++)
38073  {
38074  const double dist =
38075  final_vertex_of_previous_segment[i] -
38076  (*vector_vertex_node.begin())[i];
38077  error += dist*dist;
38078  }
38079  error = sqrt(error);
38080 
38081  //If the error is bigger than the tolerance then
38082  //we probably need to reverse, but better check
38083  if(error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
38084  {
38085  //Find the error between the final vertex of the previous
38086  //line and the last vertex of the current line
38087  double rev_error = 0.0;
38088  for(unsigned i=0;i<2;i++)
38089  {
38090  const double dist =
38091  final_vertex_of_previous_segment[i] -
38092  (*--vector_vertex_node.end())[i];
38093  rev_error += dist*dist;
38094  }
38095  rev_error = sqrt(rev_error);
38096 
38097  if(rev_error >
38098  ToleranceForVertexMismatchInPolygons::Tolerable_error)
38099  {
38100  // It could be possible that the first segment be reversed
38101  // and we did not notice it because this check does not
38102  // apply for the first segment. We can verify if the first
38103  // segment is reversed by using the vertex number 1
38104  if (p == 1)
38105  {
38106  //Initial end point of previous line
38107  Vector<double> initial_vertex_of_previous_segment;
38108 
38109  initial_vertex_of_previous_segment =
38110  polygon_pt->polyline_pt(p-1)->
38111  vertex_coordinate(0);
38112 
38113  unsigned prev_seg_boundary_id =
38114  polygon_pt->curve_section_pt(p-1)->boundary_id();
38115 
38116  //Find the error between the initial vertex of the previous
38117  //line and the first vertex of the current line
38118  double error = 0.0;
38119  for(unsigned i=0;i<2;i++)
38120  {
38121  const double dist =
38122  initial_vertex_of_previous_segment[i] -
38123  (*vector_vertex_node.begin())[i];
38124  error += dist*dist;
38125  }
38126  error = sqrt(error); // Reversed only the previous one
38127 
38128  //If the error is bigger than the tolerance then
38129  //we probably need to reverse, but better check
38130  if(error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
38131  {
38132  //Find the error between the final vertex of the previous
38133  //line and the last vertex of the current line
38134  double rev_error = 0.0;
38135  for(unsigned i=0;i<2;i++)
38136  {
38137  const double dist =
38138  initial_vertex_of_previous_segment[i] -
38139  (*--vector_vertex_node.end())[i];
38140  rev_error += dist*dist;
38141  }
38142  rev_error = sqrt(rev_error); // Reversed both the current one and
38143  // the previous one
38144 
38145  if (rev_error >
38146  ToleranceForVertexMismatchInPolygons::Tolerable_error)
38147  {
38148  std::ostringstream error_stream;
38149  error_stream
38150  <<"The distance between the first node of the current\n"
38151  <<"line segment (boundary "<<bound<<") and either end of "
38152  << "the previous line segment\n"
38153  << "(boundary "<<prev_seg_boundary_id<<") is bigger than "
38154  << "the desired tolerance "
38155  << ToleranceForVertexMismatchInPolygons::Tolerable_error
38156  << ".\n"
38157  << "This suggests that the polylines defining the "
38158  << "polygonal\n"
38159  << "representation are not properly ordered.\n"
38160  << "Fail on last vertex of polyline: ("
38161  << prev_seg_boundary_id << ") and\n"
38162  << "first vertex of polyline (" << bound << ").\n"
38163  << "This should have failed when first trying to "
38164  << "construct the\npolygon.\n";
38165  throw OomphLibError(error_stream.str(),
38166  OOMPH_CURRENT_FUNCTION,
38167  OOMPH_EXCEPTION_LOCATION);
38168  }
38169  else
38170  {
38171  // Reverse both
38172  // Reverse the current vector to line up with the
38173  // previous one
38174  std::reverse(vector_vertex_node.begin(),
38175  vector_vertex_node.end());
38176 
38177  polygon_pt->polyline_pt(p-1)->reverse();
38178  }
38179  }
38180  else
38181  {
38182  // Reverse the previous one
38183  polygon_pt->polyline_pt(p-1)->reverse();
38184  }
38185 
38186  } // if p == 1
38187  else
38188  {
38189  std::ostringstream error_stream;
38190  error_stream
38191  <<"The distance between the first node of the current\n"
38192  <<"line segment (boundary " << bound << ") and either end of "
38193  <<"the previous line segment\n"
38194  <<"(boundary "<<prev_seg_boundary_id<<") is bigger than the "
38195  <<"desired tolerance " <<
38196  ToleranceForVertexMismatchInPolygons::Tolerable_error << ".\n"
38197  <<"This suggests that the polylines defining the polygonal\n"
38198  <<"representation are not properly ordered.\n"
38199  << "Fail on last vertex of polyline: ("<<prev_seg_boundary_id
38200  << ") and\nfirst vertex of polyline ("<<bound << ").\n"
38201  << "This should have failed when first trying to construct"
38202  << " the polygon.\n";
38203  throw OomphLibError(error_stream.str(),
38204  OOMPH_CURRENT_FUNCTION,
38205  OOMPH_EXCEPTION_LOCATION);
38206  }
38207  }
38208  else
38209  {
38210  //Reverse the current vector to line up with the previous one
38211  std::reverse(vector_vertex_node.begin(),vector_vertex_node.end());
38212  }
38213  } // error
38214 
38215  } // if ( p > 0 )
38216 
38217  } // if (!this->is_mesh_distributed())
38218 
38219  // --------------------------------------------------------------------
38220  // Update the polylines representation
38221  // --------------------------------------------------------------------
38222 
38223  // Always update the polylines representation, in a distributed
38224  // mesh it is necessary to update the polyline representation since
38225  // it may no longer have vertices (the boundary may not be part of
38226  // the domain in the current processor)
38227 
38228  // The new nunber of vertices
38229  n_vertex = vector_vertex_node.size();
38230 
38231  // Now update the polyline according to the new vertices
38232  TriangleMeshPolyLine *tmp_polyline_pt =
38233  new TriangleMeshPolyLine(vector_vertex_node,bound);
38234 
38235  // Create a temporal "curve section" version of the recently
38236  // created polyline
38237  TriangleMeshCurveSection *tmp_curve_section_pt = tmp_polyline_pt;
38238 
38239  // Tolerance below which the middle point can be deleted (ratio of
38240  // deflection to element length)
38241  double unrefinement_tolerance=
38242  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
38243 
38244  // Tolerance to add points
38245  double refinement_tolerance=
38246  polygon_pt->polyline_pt(p)->refinement_tolerance();
38247 
38248  // Establish refinement and unrefinement tolerance
38249  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
38250  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
38251 
38252  // Establish the maximum length constraint
38253  double maximum_length = polygon_pt->polyline_pt(p)->maximum_length();
38254  tmp_polyline_pt->set_maximum_length(maximum_length);
38255 
38256 #ifdef OOMPH_HAS_MPI
38257  // If the mesh is distributed check that the polyline still has
38258  // vertices
38259  if (this->is_mesh_distributed())
38260  {
38261  if (n_vertex >= 2)
38262  {
38263  // Pass the connection information from the old polyline to the
38264  // new one
38265  this->copy_connection_information(polygon_pt->polyline_pt(p),
38266  tmp_curve_section_pt);
38267  } // if (n_vertex >= 2)
38268  } // if (this->is_mesh_distributed())
38269  else
38270 #endif
38271  {
38272  // Pass the connection information from the old polyline to the
38273  // new one
38274  this->copy_connection_information(polygon_pt->polyline_pt(p),
38275  tmp_curve_section_pt);
38276  }
38277 
38278  // Now update the polyline according to the new vertices but first
38279  // check if the object is allowed to delete the representation or
38280  // if it should be done by other object
38281  bool delete_it_on_destructor = false;
38282 
38283  std::set<TriangleMeshCurveSection*>::iterator it =
38284  this->Free_curve_section_pt.find(polygon_pt->curve_section_pt(p));
38285 
38286  if (it!=this->Free_curve_section_pt.end())
38287  {
38288  this->Free_curve_section_pt.erase(it);
38289  delete polygon_pt->curve_section_pt(p);
38290  delete_it_on_destructor = true;
38291  }
38292 
38293  // -------------------------------------------------------
38294  // Copying the new representation
38295  polygon_pt->curve_section_pt(p) = tmp_polyline_pt;
38296 
38297  // Update the Boundary - Polyline map
38298  this->Boundary_curve_section_pt[bound] = polygon_pt->curve_section_pt(p);
38299 
38300  if (delete_it_on_destructor)
38301  {
38302  this->Free_curve_section_pt.insert(polygon_pt->curve_section_pt(p));
38303  }
38304 
38305 #ifdef OOMPH_HAS_MPI
38306  // --------- Stuff for the sub_boundaries ----- Begin section --------
38307  // Verify if need to deal with sub_boundaries
38308  if (this->is_mesh_distributed() && nsub_boundaries > 1)
38309  {
38310  // Create temporary representations for the boundaries, only to
38311  // create the mesh when calling Triangle
38312 
38313  // Clear all previous stored data
38314  this->Boundary_subpolylines[bound].clear();
38315 
38316  // Create storage for the sub-boundaries
38317  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
38318  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
38319  {
38320  // Update the polyline according to the sub set of vertices,
38321  TriangleMeshPolyLine *sub_tmp_polyline_pt =
38322  new TriangleMeshPolyLine(sub_vector_vertex_node[isub], bound, isub);
38323 
38324  // Add the sub-polyline to the container to represent the
38325  // boundary in parts
38326  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
38327 
38328  // No need to send the unrefinement/refinement and maximum
38329  // length constraints since these are only temporary
38330  // representations. These polylines can be deleted once the new
38331  // polygons that represent the distributed domain have been
38332  // created
38333 
38334  } // for (isub < nsub_boundaries)
38335 
38336  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
38337  // --------- Stuff for the sub_boundaries ----- End section ---------
38338  #endif // OOMPH_HAS_MPI
38339 
38340  // Delete the allocated memory for the geometric object that
38341  // represents the boundary
38342  delete mesh_geom_obj_pt;
38343 
38344  } // for (p < n_polyline)
38345 
38346  // Cleanup the face mesh
38347  for(unsigned p=0;p<n_polyline;p++)
38348  {
38349  face_mesh_pt[p]->flush_node_storage();
38350  delete face_mesh_pt[p];
38351  }
38352 
38353  return update_was_performed;
38354 
38355 }
38356 
38357 //======================================================================
38358 /// \short Updates the open curve but using the elements area instead
38359 /// of the default refinement and unrefinement methods
38360 //======================================================================
38361 template <class ELEMENT>
38363 update_open_curve_using_elements_area(TriangleMeshOpenCurve* &open_curve_pt,
38364  const Vector<double> &target_area)
38365 {
38366  // Verify if there was a change on the open curve representation
38367  unsigned update_was_performed = false;
38368 
38369  const unsigned nele = this->nelement();
38370 
38371  // - Get the vertices along the boundaries and for each element identify
38372  // its associated target error.
38373  // - Get face mesh representation of each polyline.
38374  // - Get the vertices with the help of face elements.
38375  // - Find the global index in the mesh of the face element
38376  // and use it to get its associated target area.
38377 
38378  // Get the face mesh representation
38379  Vector<Mesh*> face_mesh_pt;
38380  get_face_mesh_representation(open_curve_pt,face_mesh_pt);
38381 
38382  // Create vertices of the polylines by using the vertices of the
38383  // FaceElements
38384  Vector<double> vertex_coord(3); // zeta,x,y
38385  Vector<double> bound_left(1);
38386  Vector<double> bound_right(1);
38387 
38388  const unsigned ncurve_section = open_curve_pt->ncurve_section();
38389 
38390  // Go for each curve section
38391  for(unsigned cs = 0; cs < ncurve_section; cs++)
38392  {
38393  // Get the MeshAsGeomObject representation just once per polyline,
38394  // this object is only used by the
38395  // refine_boundary_constrained_by_target_area() method. We get it
38396  // here to ensure that all processors (in a distributed context)
38397  // get this representation just once, and because an AllToAll MPI
38398  // communication is used in this calling
38399  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt[cs]);
38400 
38401  //Get the boundary id
38402  const unsigned bound =
38403  open_curve_pt->curve_section_pt(cs)->boundary_id();
38404 
38405  // Get the chunk number
38406  const unsigned chunk =
38407  open_curve_pt->curve_section_pt(cs)->boundary_chunk();
38408 
38409  /// Use a vector of vector for vertices and target areas to deal
38410  /// with the cases when the boundaries are split by the
38411  /// distribution process. Internal boundaries may be completely or
38412  /// partially overlapped by shared boundaries
38413 
38414  // Loop over the face elements and add their vertices (they are
38415  // automatically sorted because of the set)
38416  const unsigned nface_element = face_mesh_pt[cs]->nelement();
38417 
38418  // Store the non halo elements and the element at the other side of
38419  // the boundary (whatever it be halo or not), the first will be the
38420  // ones from which we will get the vertices (in even position)
38421  Vector<FiniteElement*> non_halo_doubled_face_element_pt;
38422 
38423  // Map to store the index of the face element on a boundary
38424  std::map<FiniteElement*,unsigned> face_element_index_on_boundary;
38425 
38426  // Map to know the already sorted face elements
38427  std::map<FiniteElement*,bool> face_element_done;
38428 
38429  for(unsigned ef = 0; ef < nface_element; ++ef)
38430  {
38431  FiniteElement* ele_face_pt = face_mesh_pt[cs]->finite_element_pt(ef);
38432 
38433  // Skip the halo elements (not used as base elements, only
38434  // include those elements whose element at the other side of the
38435  // boundary is non halo)
38436 #ifdef OOMPH_HAS_MPI
38437  if (this->is_mesh_distributed())
38438  {
38439  // Only work with non-halo elements
38440  if (ele_face_pt->is_halo()) {continue;}
38441  }
38442 #endif
38443 
38444  // Check if not already done
38445  if (!face_element_done[ele_face_pt])
38446  {
38447  // Add the element and look for the element at the other side
38448  // of the boundary to add it immediately after the new added
38449  // element
38450  non_halo_doubled_face_element_pt.push_back(ele_face_pt);
38451  // Create the map of the face element with the index
38452  face_element_index_on_boundary[ele_face_pt] = ef;
38453  // Mark the current element as done
38454  face_element_done[ele_face_pt] = true;
38455  // Get the number of nodes
38456  const unsigned nnodes = ele_face_pt->nnode();
38457  // Get the left and right node to look for the elements at the
38458  // other side of the boundary
38459  Node* left_node_pt = ele_face_pt->node_pt(0);
38460  Node* right_node_pt = ele_face_pt->node_pt(nnodes-1);
38461 #ifdef PARANOID
38462  // Flag to know if the element at the other side of the
38463  // boundary was found
38464  bool found_other_side_face_ele = false;
38465 #endif
38466  for (unsigned iface = 0; iface < nface_element; iface++)
38467  {
38468  // Get the candidate face element
38469  FiniteElement *cele_face_pt =
38470  face_mesh_pt[cs]->finite_element_pt(iface);
38471  // Check if not already done
38472  if (!face_element_done[cele_face_pt])
38473  {
38474  Node* cleft_node_pt = cele_face_pt->node_pt(0);
38475  Node* cright_node_pt = cele_face_pt->node_pt(nnodes-1);
38476  // Check if the nodes are the same
38477  if ((left_node_pt == cleft_node_pt &&
38478  right_node_pt == cright_node_pt) ||
38479  (left_node_pt == cright_node_pt &&
38480  right_node_pt == cleft_node_pt))
38481  {
38482  // Add the element to the storage
38483  non_halo_doubled_face_element_pt.push_back(cele_face_pt);
38484  // ... and mark the element as done
38485  face_element_done[cele_face_pt] = true;
38486  // Create the map of the face element with the index
38487  face_element_index_on_boundary[cele_face_pt] = iface;
38488 #ifdef PARANOID
38489  // Set the flag of found other side face element
38490  found_other_side_face_ele = true;
38491 #endif
38492  break;
38493  }
38494  }
38495  } // (iface < nface_element)
38496 
38497 #ifdef PARANOID
38498  if (!found_other_side_face_ele)
38499  {
38500  std::ostringstream error_message;
38501  error_message
38502  << "The face element at the other side of the boundary ("
38503  << bound << ") was not found!!\n"
38504  << "These are the nodes of the face element:\n"
38505  << "("<<left_node_pt->x(0)<<", "<<left_node_pt->x(1)<<") "
38506  << "and ("<<right_node_pt->x(0)<<","<<right_node_pt->x(1)<<")\n\n";
38507  throw OomphLibError(error_message.str(),
38508  "RefineableTriangleMesh::update_open_curve_using_elements_area()",
38509  OOMPH_EXCEPTION_LOCATION);
38510  }
38511 #endif
38512  } // if (!face_ele_done[ele_face_pt])
38513 
38514  } // (ef < nface_element)
38515 
38516  // Clear the map of the already done face elements
38517  // This will be used to help sorting the face elements
38518  face_element_done.clear();
38519 
38520  // Set of coordinates that are on the boundary
38521  // The entries are sorted on first entry in vector which stores
38522  // the boundary coordinate so the vertices come out in order!
38523  std::set<Vector<double> > vertex_nodes;
38524 
38525  // Vector to store the vertices, transfer the sorted vertices from the
38526  // set to this vector, --- including the z-value ---
38527  Vector<Vector<double> > tmp_vector_vertex_node;
38528 
38529  // Vector to store the coordinates of the polylines, same as the
38530  // tmp_vector_vertex_node vector (after adding more nodes) but
38531  // --- without the z-value ---, used to re-generate the polylines
38532  Vector<Vector<double> > vector_vertex_node;
38533 
38534 #ifdef OOMPH_HAS_MPI
38535  // Indicates if the set of vertices give rise to a internal
38536  // boundary that will be used as shared boundary or as normal
38537  // internal boundary -- Only used to deal with internal boundaries
38538  // in a distributed scheme
38539  std::vector<bool> internal_to_shared_boundary;
38540 
38541  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
38542  // Set of coordinates that are on the boundary (splitted boundary version)
38543  // The first vector is used to allocate the points for each sub-boundary
38544  // Set entries are ordered on first entry in vector which stores
38545  // the boundary coordinate so the vertices come out in order!
38546  Vector<std::set<Vector<double> > > sub_vertex_nodes;
38547 
38548  // Vector to store the vertices, transfer the sorted vertices from the
38549  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
38550  Vector<Vector<Vector<double> > > sub_tmp_vector_vertex_node;
38551 
38552  // Vector to store the coordinates of the polylines that will represent
38553  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
38554  // but --- without the z-value ---, used to generate the sub-polylines
38555  Vector<Vector<Vector<double> > > sub_vector_vertex_node;
38556 
38557  // --------- Stuff to deal with splitted boundaries ----------- End ------
38558 
38559 #endif // #ifdef OOMPH_HAS_MPI
38560 
38561  // Sort the face element, those that have both elements (one at
38562  // each side of the boundary) marked as nonhalo, and those with one
38563  // nonhalo an the other as halo
38564 
38565  // Number of done face elements
38566  unsigned nsorted_face_elements = 0;
38567 
38568 #ifdef OOMPH_HAS_MPI
38569  // Counter for sub_boundaries
38570  unsigned nsub_boundaries = 0;
38571 #endif // #ifdef OOMPH_HAS_MPI
38572 
38573  // Total number of non halo double face element
38574  const unsigned nnon_halo_doubled_face_ele =
38575  non_halo_doubled_face_element_pt.size();
38576 
38577  // Continue until all the face elements have been sorted
38578  // This while is to deal with the cases of splitted boundaries
38579  while(nsorted_face_elements < nnon_halo_doubled_face_ele)
38580  {
38581  // Get and initial face element
38582  FiniteElement* ele_face_pt = 0;
38583  FiniteElement* repeated_ele_face_pt = 0;
38584 #ifdef PARANOID
38585  bool found_initial_face_element = false;
38586 #endif
38587 
38588  // Flag to know if we are working with a face element which the
38589  // face element at the other side of the boundary is also non
38590  // halo
38591  bool both_root_face_elements_are_nonhalo = false;
38592 
38593  unsigned iface = 0;
38594  for (iface = 0; iface < nnon_halo_doubled_face_ele; iface+=2)
38595  {
38596  ele_face_pt = non_halo_doubled_face_element_pt[iface];
38597  // If not done then take it as initial face element
38598  if (!face_element_done[ele_face_pt])
38599  {
38600  // Mark it as done
38601  face_element_done[ele_face_pt] = true;
38602  // Get the other side boundary face element
38603  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iface+1];
38604  // ... also mark as done the repeated face element
38605  face_element_done[repeated_ele_face_pt] = true;
38606 
38607 #ifdef OOMPH_HAS_MPI
38608  if (!repeated_ele_face_pt->is_halo())
38609  {both_root_face_elements_are_nonhalo = true;}
38610 #endif // #ifdef OOMPH_HAS_MPI
38611 
38612  // Plus two because internal boundaries have
38613  // two face elements per each edge
38614  nsorted_face_elements+=2;
38615  iface+=2;
38616 #ifdef PARANOID
38617  // And set the flag to true
38618  found_initial_face_element = true;
38619 #endif
38620  break;
38621  }
38622  }
38623 
38624 #ifdef PARANOID
38625  if (!found_initial_face_element)
38626  {
38627  std::ostringstream error_message;
38628  error_message
38629  <<"Could not find an initial face element for the current segment\n";
38630  throw OomphLibError(error_message.str(),
38631  OOMPH_CURRENT_FUNCTION,
38632  OOMPH_EXCEPTION_LOCATION);
38633  }
38634 #endif
38635 
38636  // Local set of coordinates that are on the boundary Set entries
38637  // are ordered on first entry in vector which stores the boundary
38638  // coordinate so the vertices come out in order
38639  std::set<Vector<double> > local_vertex_nodes;
38640 
38641  // Vector to store the vertices, transfer the sorted vertices from the
38642  // set (local) to this vector (local), --- including the z-value ---
38643  Vector<Vector<double> > local_tmp_vector_vertex_node;
38644 
38645  // Vector to store the target areas, uses the same approach as the
38646  // set for the local_vertex_nodes, ordered on first entry
38647  std::set<Vector<double> > sorted_target_areas;
38648 
38649  // Vector to store the target areas, used to transfer the sorted target
38650  // areas from "sorted_target_areas" set
38651  Vector<double> tmp_sorted_target_areas;
38652 
38653  // ------------------------------------------------------------------
38654  // Add the vertices of the initial face element to the set of local
38655  // sorted vertices
38656  // ------------------------------------------------------------------
38657  const unsigned nnode = ele_face_pt->nnode();
38658  // Add the left-hand node to the set:
38659  // Boundary coordinate
38660  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound,bound_left);
38661  vertex_coord[0] = bound_left[0];
38662 
38663  // Actual coordinates
38664  for(unsigned i=0;i<2;i++)
38665  {
38666  vertex_coord[i+1] = ele_face_pt->node_pt(0)->x(i);
38667  }
38668  local_vertex_nodes.insert(vertex_coord);
38669 
38670  // Add the right-hand node to the set:
38671  // Boundary coordinate
38672  ele_face_pt->node_pt(nnode-1)->get_coordinates_on_boundary(bound,
38673  bound_right);
38674  vertex_coord[0] = bound_right[0];
38675 
38676  // Actual coordinates
38677  for(unsigned i=0;i<2;i++)
38678  {
38679  vertex_coord[i+1] = ele_face_pt->node_pt(nnode-1)->x(i);
38680  }
38681  local_vertex_nodes.insert(vertex_coord);
38682 
38683  // The initial and final node on the set
38684  Node *first_node_pt = ele_face_pt->node_pt(0);
38685  Node *last_node_pt = ele_face_pt->node_pt(nnode-1);
38686 
38687  // -----------------------------------------------------
38688  // Find the global index in the mesh of the face element
38689  // and use it to get its associated target area
38690  // -----------------------------------------------------
38691  // Container to store the zeta value (used as index) and
38692  // the associated target area of the element
38693  Vector<double> zeta_target_area_values(2);
38694 
38695  // Use the minimum zeta value to sort the target areas
38696  // along the boundary
38697  zeta_target_area_values[0] = std::min(bound_left[0], bound_right[0]);
38698 
38699  // Get the index of the face element on the current boundary
38700  const unsigned ef = face_element_index_on_boundary[ele_face_pt];
38701  // Get the "ef"-th element on the boundary
38702  FiniteElement *el_pt = this->boundary_element_pt(bound, ef);
38703  double target_area_face_element = 0.0;
38704 
38705 #ifdef PARANOID
38706  bool found_global_element_index = false;
38707 #endif
38708  for (unsigned eg = 0 ; eg < nele; eg++)
38709  {
38710  // Get the "eg-th" element
38711  FiniteElement *el_compare_pt = this->finite_element_pt(eg);
38712 
38713  // Compare with the element on the boundary, if equal then
38714  // store the target area
38715  if (el_pt == el_compare_pt)
38716  {
38717  target_area_face_element = target_area[eg];
38718 #ifdef PARANOID
38719  found_global_element_index = true;
38720 #endif
38721  break; // break the for (eg < nele) global element
38722  } // if el_pt == el_compare_pt
38723  } // for nele (on complete mesh)
38724 
38725 #ifdef PARANOID
38726  if (!found_global_element_index)
38727  {
38728  std::ostringstream error_message;
38729  error_message
38730  << "The global index for the ("<< ef <<")-th face element "
38731  << "on\nthe ("<< bound <<")-th boundary was not found!!!";
38732  throw OomphLibError(error_message.str(),
38733  OOMPH_CURRENT_FUNCTION,
38734  OOMPH_EXCEPTION_LOCATION);
38735  }
38736 #endif
38737 
38738  // Get the index of the repeated face element on the current boundary
38739  const unsigned ref = face_element_index_on_boundary[repeated_ele_face_pt];
38740  FiniteElement *rel_pt = this->boundary_element_pt(bound, ref);
38741  double target_area_repeated_face_element = 0.0;
38742 
38743 #ifdef PARANOID
38744  bool found_global_repeated_element_index = false;
38745 #endif
38746  for (unsigned eg = 0 ; eg < nele; eg++)
38747  {
38748  // Get the "eg-th" element
38749  FiniteElement *el_compare_pt = this->finite_element_pt(eg);
38750 
38751  // Compare with the element on the boundary, if equal then
38752  // store the target area
38753  if (rel_pt == el_compare_pt)
38754  {
38755  target_area_repeated_face_element = target_area[eg];
38756 #ifdef PARANOID
38757  found_global_repeated_element_index = true;
38758 #endif
38759  break; // break the for (eg < nele) global element
38760  } // if rel_pt == el_compare_pt
38761  } // for nele (on complete mesh)
38762 
38763 #ifdef PARANOID
38764  if (!found_global_repeated_element_index)
38765  {
38766  std::ostringstream error_message;
38767  error_message
38768  << "The global index for the ("<< ref <<")-th face element "
38769  << "on\nthe ("<< bound <<")-th boundary was not found (repeated "
38770  << "face element)!!!";
38771  throw OomphLibError(error_message.str(),
38772  OOMPH_CURRENT_FUNCTION,
38773  OOMPH_EXCEPTION_LOCATION);
38774  }
38775 #endif
38776 
38777  // Choose the minimum target area from both elements, one at each side
38778  // of the edge on the boundary
38779  zeta_target_area_values[1]=std::min(target_area_face_element,
38780  target_area_repeated_face_element);
38781 
38782  // Add the target areas to the sorted set
38783  sorted_target_areas.insert(zeta_target_area_values);
38784  // ------------------------------------------------------------------
38785 
38786  // Continue iterating if a new face element has been added to the
38787  // list
38788  bool face_element_added = false;
38789 
38790  // While a new face element has been added to the set of sorted
38791  // face elements then re-iterate
38792  do
38793  {
38794  // Start from the next face elements since we have already
38795  // added the previous one as the initial face element (any
38796  // previous face element had to be added on previous
38797  // iterations)
38798  for (unsigned iiface=iface;
38799  iiface<nnon_halo_doubled_face_ele;iiface+=2)
38800  {
38801  face_element_added = false;
38802  ele_face_pt = non_halo_doubled_face_element_pt[iiface];
38803 
38804  // Check that the face element with which we are working has
38805  // the same conditions as the root face element (both faces
38806  // are nonhalo or one face is halo and the other nonhalo)
38807 
38808  // Get the face element at the other side of the boundary
38809  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iiface+1];
38810  bool both_face_elements_are_nonhalo = false;
38811 
38812 #ifdef OOMPH_HAS_MPI
38813  if (!repeated_ele_face_pt->is_halo())
38814  {both_face_elements_are_nonhalo = true;}
38815 #endif // #ifdef OOMPH_HAS_MPI
38816 
38817  if (!face_element_done[ele_face_pt] &&
38818  (both_face_elements_are_nonhalo ==
38819  both_root_face_elements_are_nonhalo))
38820  {
38821  // Get each individual node to check if they are contiguous
38822  const unsigned nlnode = ele_face_pt->nnode();
38823  Node* left_node_pt = ele_face_pt->node_pt(0);
38824  Node* right_node_pt = ele_face_pt->node_pt(nlnode-1);
38825 
38826  if (left_node_pt == first_node_pt)
38827  {
38828  first_node_pt = right_node_pt;
38829  face_element_added = true;
38830  }
38831  else if (left_node_pt == last_node_pt)
38832  {
38833  last_node_pt = right_node_pt;
38834  face_element_added = true;
38835  }
38836  else if (right_node_pt == first_node_pt)
38837  {
38838  first_node_pt = left_node_pt;
38839  face_element_added = true;
38840  }
38841  else if (right_node_pt == last_node_pt)
38842  {
38843  last_node_pt = left_node_pt;
38844  face_element_added = true;
38845  }
38846 
38847  if (face_element_added)
38848  {
38849  // Add the left-hand node to the set:
38850  // Boundary coordinate
38851  left_node_pt->get_coordinates_on_boundary(bound,bound_left);
38852  vertex_coord[0] = bound_left[0];
38853 
38854  // Actual coordinates
38855  for(unsigned i=0;i<2;i++)
38856  {
38857  vertex_coord[i+1] = left_node_pt->x(i);
38858  }
38859  local_vertex_nodes.insert(vertex_coord);
38860 
38861  // Add the right-hand nodes to the set:
38862  // Boundary coordinate
38863  right_node_pt->get_coordinates_on_boundary(bound,bound_right);
38864  vertex_coord[0] = bound_right[0];
38865 
38866  // Actual coordinates
38867  for(unsigned i=0;i<2;i++)
38868  {
38869  vertex_coord[i+1] = right_node_pt->x(i);
38870  }
38871  local_vertex_nodes.insert(vertex_coord);
38872 
38873  // Mark as done only if one of its nodes has been
38874  // added to the list
38875  face_element_done[ele_face_pt] = true;
38876  // .. also mark as done the face element at the othe side of
38877  // the boundary
38878  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iiface+1];
38879  face_element_done[repeated_ele_face_pt] = true;
38880  // ... and increase the number of sorted face elements
38881  nsorted_face_elements+=2;
38882 
38883  // -----------------------------------------------------
38884  // Find the global index in the mesh of the face element
38885  // and use it to get its associated target area
38886  // -----------------------------------------------------
38887  // Use the minimum zeta value to sort the target areas
38888  // along the boundary
38889  zeta_target_area_values[0] =
38890  std::min(bound_left[0], bound_right[0]);
38891 
38892  // Get the "ef"-th element on the boundary
38893  const unsigned lef = face_element_index_on_boundary[ele_face_pt];
38894  FiniteElement *lel_pt = this->boundary_element_pt(bound, lef);
38895 
38896 #ifdef PARANOID
38897  found_global_element_index = false;
38898 #endif
38899  for (unsigned eg = 0 ; eg < nele; eg++)
38900  {
38901  // Get the "eg-th" element
38902  FiniteElement *lel_compare_pt = this->finite_element_pt(eg);
38903 
38904  // Compare with the element on the boundary, if equal then
38905  // store the target area
38906  if (lel_pt == lel_compare_pt)
38907  {
38908  target_area_face_element = target_area[eg];
38909 #ifdef PARANOID
38910  found_global_element_index = true;
38911 #endif
38912  break; // break the for (eg < nele) global element
38913  } // if lel_pt == lel_compare_pt
38914  } // for nele (on complete mesh)
38915 
38916 #ifdef PARANOID
38917  if (!found_global_element_index)
38918  {
38919  std::ostringstream error_message;
38920  error_message
38921  << "The global index for the ("<< lef <<")-th face element "
38922  << "on\nthe ("<< bound <<")-th boundary was not found!!!";
38923  throw OomphLibError(error_message.str(),
38924  OOMPH_CURRENT_FUNCTION,
38925  OOMPH_EXCEPTION_LOCATION);
38926  }
38927 #endif
38928 
38929  // Get the index of the repeated face element on the boundary
38930  const unsigned rlef =
38931  face_element_index_on_boundary[repeated_ele_face_pt];
38932  FiniteElement *rlel_pt = this->boundary_element_pt(bound, rlef);
38933 
38934 #ifdef PARANOID
38935  found_global_repeated_element_index = false;
38936 #endif
38937  for (unsigned eg = 0 ; eg < nele; eg++)
38938  {
38939  // Get the "eg-th" element
38940  FiniteElement *lel_compare_pt = this->finite_element_pt(eg);
38941 
38942  // Compare with the element on the boundary, if equal then
38943  // store the target area
38944  if (rlel_pt == lel_compare_pt)
38945  {
38946  target_area_repeated_face_element = target_area[eg];
38947 #ifdef PARANOID
38948  found_global_repeated_element_index = true;
38949 #endif
38950  break; // break the for (eg < nele) global element
38951  } // if rlel_pt == el_compare_pt
38952  } // for nele (on complete mesh)
38953 
38954 #ifdef PARANOID
38955  if (!found_global_repeated_element_index)
38956  {
38957  std::ostringstream error_message;
38958  error_message
38959  << "The global index for the ("<< rlef <<")-th face element "
38960  << "on\nthe ("<< bound <<")-th boundary was not found "
38961  << "(repeated face element)!!!";
38962  throw OomphLibError(error_message.str(),
38963  OOMPH_CURRENT_FUNCTION,
38964  OOMPH_EXCEPTION_LOCATION);
38965  }
38966 #endif
38967 
38968  // Choose the minimum target area from both elements, one
38969  // at each side of the edge on the boundary
38970  zeta_target_area_values[1] =
38971  std::min(target_area_face_element,
38972  target_area_repeated_face_element);
38973 
38974  // Add the target areas to the sorted set
38975  sorted_target_areas.insert(zeta_target_area_values);
38976 
38977  break;
38978  }
38979 
38980  } // if (!face_element_done[[ele_face_pt])
38981  } // for (iiface<nnon_halo_doubled_face_ele)
38982  }while(face_element_added &&
38983  (nsorted_face_elements < nnon_halo_doubled_face_ele));
38984 
38985  // -------------------------------------------------------------
38986  // At this point we already have a sorted set of nodes and can
38987  // be used to peform the unrefinement and refinement procedures
38988  // -------------------------------------------------------------
38989 
38990  // Get the number of nodes on the list
38991  const unsigned nlocal_nodes = local_vertex_nodes.size();
38992  // Change representation to vector for easy of handling ...
38993  local_tmp_vector_vertex_node.resize(nlocal_nodes);
38994 
38995  // Copy the vertices of the nodes
38996  unsigned counter = 0;
38997  std::set<Vector<double> >::iterator it_vertex;
38998  for (it_vertex = local_vertex_nodes.begin();
38999  it_vertex != local_vertex_nodes.end();
39000  it_vertex++)
39001  {
39002  local_tmp_vector_vertex_node[counter].resize(3);
39003  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
39004  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
39005  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
39006  counter++;
39007  }
39008 
39009  // ... same for the info. related with the target areas (turn
39010  // into vector)
39011  const unsigned ntarget_areas = sorted_target_areas.size();
39012  tmp_sorted_target_areas.resize(ntarget_areas);
39013  counter = 0;
39014  std::set<Vector<double> >::iterator it_area;
39015  for(it_area = sorted_target_areas.begin();
39016  it_area != sorted_target_areas.end();
39017  ++it_area)
39018  {
39019  tmp_sorted_target_areas[counter] = (*it_area)[1];
39020  ++counter;
39021  }
39022 
39023 #ifdef PARANOID
39024  if (nlocal_nodes > 0 && (ntarget_areas != nlocal_nodes - 1) )
39025  {
39026  std::ostringstream error_message;
39027  error_message
39028  << "The boundary (" << bound << ") was split during the "
39029  << "distribution process.\n"
39030  << "The problem comes when associating the target areas with the "
39031  << "elements that gave\nrise to the vertex coordinates.\n"
39032  << "The number of local nodes on the 'sub-polyline' ("
39033  << nlocal_nodes << ") is not according with the number of target\n"
39034  << "areas ("<< ntarget_areas << ") for that number of nodes.\n"
39035  << "The target areas number must be equal to the number of nodes-1\n";
39036  throw OomphLibError(error_message.str(),
39037  OOMPH_CURRENT_FUNCTION,
39038  OOMPH_EXCEPTION_LOCATION);
39039  }
39040 #endif
39041 
39042  // The unrefinement and refinement process needs to be applied
39043  // from the bottom-left node since the internal open curve could
39044  // lie on the shared boundaries
39045  if (local_tmp_vector_vertex_node[nlocal_nodes-1][2] <
39046  local_tmp_vector_vertex_node[0][2])
39047  {
39048  std::reverse(local_tmp_vector_vertex_node.begin(),
39049  local_tmp_vector_vertex_node.end());
39050  std::reverse(tmp_sorted_target_areas.begin(),
39051  tmp_sorted_target_areas.end());
39052  }
39053  else if (local_tmp_vector_vertex_node[nlocal_nodes-1][2] ==
39054  local_tmp_vector_vertex_node[0][2])
39055  {
39056  if (local_tmp_vector_vertex_node[nlocal_nodes-1][1] <
39057  local_tmp_vector_vertex_node[0][1])
39058  {
39059  std::reverse(local_tmp_vector_vertex_node.begin(),
39060  local_tmp_vector_vertex_node.end());
39061  std::reverse(tmp_sorted_target_areas.begin(),
39062  tmp_sorted_target_areas.end());
39063  }
39064  }
39065 
39066  // ------------------------------------------------------------
39067  // Create the vertices along the boundary using the target
39068  // area to define the distance among them
39069  // ------------------------------------------------------------
39070 
39071  // Tolerance below which the middle point can be deleted
39072  // (ratio of deflection to element length)
39073  double unrefinement_tolerance=
39074  open_curve_pt->polyline_pt(cs)->unrefinement_tolerance();
39075 
39076  // Apply unrefinement
39077  bool unrefinement_applied =
39078  unrefine_boundary_constrained_by_target_area(
39079  bound, chunk, local_tmp_vector_vertex_node,
39080  unrefinement_tolerance, tmp_sorted_target_areas);
39081 
39082  // Tolerance for refinement
39083  double refinement_tolerance=
39084  open_curve_pt->polyline_pt(cs)->refinement_tolerance();
39085 
39086  // Apply refinement
39087  bool refinement_applied =
39088  refine_boundary_constrained_by_target_area(
39089  mesh_geom_obj_pt, local_tmp_vector_vertex_node,
39090  refinement_tolerance, tmp_sorted_target_areas);
39091 
39092  // Clear the local containter to recover the nodes ordered using
39093  // the zeta value
39094  local_vertex_nodes.clear();
39095 
39096  // At the end of each unrefinement/refinement step store the new
39097  // nodes on the set that will give rise to the vertices of the
39098  // new polyline representation
39099  const unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
39100  for (unsigned i = 0; i < nnew_nodes; i++)
39101  {
39102  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
39103  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
39104  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
39105  vertex_nodes.insert(vertex_coord); // Global container
39106  local_vertex_nodes.insert(vertex_coord);
39107  }
39108 
39109  // Update the flag to indicate whether an unrefinement or
39110  // refinement was applied
39111  update_was_performed = (unrefinement_applied || refinement_applied);
39112 
39113 #ifdef OOMPH_HAS_MPI
39114  if (this->is_mesh_distributed())
39115  {
39116  // Add the set of vertices for the boundary, this will help to
39117  // detect if we need to deal with sub_boundaries and
39118  // sub_polylines representations
39119  sub_vertex_nodes.push_back(local_vertex_nodes);
39120  // Increase the counter for sub_boundaries
39121  nsub_boundaries++;
39122 
39123  // Mark if the polyline created by these vertices will be used
39124  // as a shared boundary or as an internal boundary
39125  if (both_root_face_elements_are_nonhalo)
39126  {internal_to_shared_boundary.push_back(false);}
39127  else
39128  {internal_to_shared_boundary.push_back(true);}
39129  }
39130 #endif
39131 
39132  } // while(nsorted_face_elements < nnon_halo_doubled_face_ele)
39133  // This while is in charge of sorting all the face elements to
39134  // create the new representation of the polyline (also deals
39135  // with the sub-boundary cases)
39136 
39137  // Now turn into vector for ease of handling...
39138  const unsigned npoly_vertex = vertex_nodes.size();
39139  tmp_vector_vertex_node.resize(npoly_vertex);
39140  unsigned count = 0;
39141  for (std::set<Vector<double> >::iterator it = vertex_nodes.begin();
39142  it!=vertex_nodes.end(); ++it)
39143  {
39144  tmp_vector_vertex_node[count].resize(3);
39145  tmp_vector_vertex_node[count][0] = (*it)[0];
39146  tmp_vector_vertex_node[count][1] = (*it)[1];
39147  tmp_vector_vertex_node[count][2] = (*it)[2];
39148  ++count;
39149  }
39150 
39151 #ifdef OOMPH_HAS_MPI
39152  // Check that the number of set of vertices marked to be part of a
39153  // shared boundary or of an internal boundaries be the same as the
39154  // total number of sub-boundaries
39155 #ifdef PARANOID
39156  const unsigned nsub_boundaries_set = sub_vertex_nodes.size();
39157  const unsigned ninternal_to_shared_boundaries =
39158  internal_to_shared_boundary.size();
39159  if (nsub_boundaries_set != ninternal_to_shared_boundaries)
39160  {
39161  std::ostringstream error_message;
39162  error_message
39163  << "The number of found sub-boundaries and the number of marked "
39164  << "internal\nboundaries are different\n"
39165  << "Number of found sub-boundaries: ("<<nsub_boundaries_set<<")\n"
39166  << "Number of marked internal boundaries: ("
39167  << ninternal_to_shared_boundaries << ")\n\n";
39168  throw OomphLibError(error_message.str(),
39169  OOMPH_CURRENT_FUNCTION,
39170  OOMPH_EXCEPTION_LOCATION);
39171  }
39172 #endif
39173 
39174  // --------- Stuff for the sub_boundaries ----- Begin section -------
39175 #ifdef PARANOID
39176  if (nsub_boundaries_set != nsub_boundaries)
39177  {
39178  std::ostringstream error_message;
39179  error_message
39180  << "The number of found sub-boundaries and the number of counted\n"
39181  << "sub-boundaries are different:\n"
39182  << "Number of found sub-boundaries: ("<<nsub_boundaries_set<<")\n"
39183  << "Number of counted sub-boundaries: ("<<nsub_boundaries<<")\n\n";
39184  throw OomphLibError(error_message.str(),
39185  OOMPH_CURRENT_FUNCTION,
39186  OOMPH_EXCEPTION_LOCATION);
39187  }
39188 #endif
39189 
39190  // Verify if need to deal with sub_boundaries
39191  if (this->is_mesh_distributed() && nsub_boundaries > 1)
39192  {
39193  // Mark the boundary as been splitted in the partition process
39194  this->Boundary_was_splitted[bound] = true;
39195 
39196  // Resize the vector to store the info. of sub-boundaries
39197  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
39198  // Loop over the sub-boundaries
39199  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
39200  {
39201  // Turn info. into vector for ease of handling...
39202  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
39203  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
39204  unsigned subcount = 0;
39205  std::set<Vector<double> >::iterator subit;
39206  for(subit = sub_vertex_nodes[isub].begin();
39207  subit != sub_vertex_nodes[isub].end(); ++subit)
39208  {
39209  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
39210  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
39211  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
39212  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
39213  ++subcount;
39214  }
39215  }
39216  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
39217  // --------- Stuff for the sub_boundaries ----- End section ----------
39218 #endif // OOMPH_HAS_MPI
39219 
39220  // For further processing the three-dimensional vector has to be
39221  // reduced to a two-dimensional vector
39222  unsigned n_vertex=tmp_vector_vertex_node.size();
39223 
39224  // Resize the vector for vectices
39225  vector_vertex_node.resize(n_vertex);
39226  for(unsigned i=0;i<n_vertex;i++)
39227  {
39228  vector_vertex_node[i].resize(2);
39229  vector_vertex_node[i][0]=tmp_vector_vertex_node[i][1];
39230  vector_vertex_node[i][1]=tmp_vector_vertex_node[i][2];
39231  }
39232 
39233 #ifdef OOMPH_HAS_MPI
39234  // --------- Stuff for the sub_boundaries ----- Begin section -------
39235  // Verify if need to deal with sub_boundaries
39236  if (this->is_mesh_distributed() && nsub_boundaries > 1)
39237  {
39238  // For further processing the three-dimensional vector has to be
39239  // reduced to a two-dimensional vector
39240  // Resize the vector to store the info. of sub-boundaries
39241  sub_vector_vertex_node.resize(nsub_boundaries);
39242  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
39243  {
39244  const unsigned subn_vertex =
39245  sub_tmp_vector_vertex_node[isub].size();
39246  // Resize the vector for vectices
39247  sub_vector_vertex_node[isub].resize(subn_vertex);
39248  for(unsigned i=0;i<subn_vertex;i++)
39249  {
39250  sub_vector_vertex_node[isub][i].resize(2);
39251  sub_vector_vertex_node[isub][i][0]=
39252  sub_tmp_vector_vertex_node[isub][i][1];
39253  sub_vector_vertex_node[isub][i][1]=
39254  sub_tmp_vector_vertex_node[isub][i][2];
39255  }
39256  }
39257  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
39258 
39259  // We already have the info. for the sub-boundaries (if necessary)
39260  // and then we can create the sub-boundaries representations to
39261  // ease the generation of the mesh by Triangle
39262 
39263  // --------- Stuff for the sub_boundaries ----- End section ---------
39264 #endif // OOMPH_HAS_MPI
39265 
39266  // ------------------------------------------------------------------
39267  // Check for contiguousness
39268  // ------------------------------------------------------------------
39269 #ifdef OOMPH_HAS_MPI
39270  // Only perform this checking if the mesh is not distributed When
39271  // the mesh is distributed the polylines continuity is addressed by
39272  // the sort_polylines_helper() method
39273  if (!this->is_mesh_distributed())
39274 #endif
39275  {
39276  if ( cs > 0 )
39277  {
39278  //Final end point of previous line
39279  Vector<double> final_vertex_of_previous_segment;
39280  unsigned n_prev_vertex =
39281  open_curve_pt->curve_section_pt(cs-1)->nvertex();
39282  final_vertex_of_previous_segment =
39283  open_curve_pt->polyline_pt(cs-1)->
39284  vertex_coordinate(n_prev_vertex-1);
39285 
39286  unsigned prev_seg_boundary_id =
39287  open_curve_pt->curve_section_pt(cs-1)->boundary_id();
39288 
39289  //Find the error between the final vertex of the previous
39290  //line and the first vertex of the current line
39291  double error = 0.0;
39292  for(unsigned i=0;i<2;i++)
39293  {
39294  const double dist =
39295  final_vertex_of_previous_segment[i] -
39296  (*vector_vertex_node.begin())[i];
39297  error += dist*dist;
39298  }
39299  error = sqrt(error);
39300 
39301  //If the error is bigger than the tolerance then
39302  //we probably need to reverse, but better check
39303  if(error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
39304  {
39305  //Find the error between the final vertex of the previous
39306  //line and the last vertex of the current line
39307  double rev_error = 0.0;
39308  for(unsigned i=0;i<2;i++)
39309  {
39310  const double dist =
39311  final_vertex_of_previous_segment[i] -
39312  (*--vector_vertex_node.end())[i];
39313  rev_error += dist*dist;
39314  }
39315  rev_error = sqrt(rev_error);
39316 
39317  if(rev_error >
39318  ToleranceForVertexMismatchInPolygons::Tolerable_error)
39319  {
39320  // It could be possible that the first segment be reversed and we
39321  // did not notice it because this check does not apply for the
39322  // first segment. We can verify if the first segment is reversed
39323  // by using the vertex number 1
39324  if (cs == 1)
39325  {
39326  //Initial end point of previous line
39327  Vector<double> initial_vertex_of_previous_segment;
39328 
39329  initial_vertex_of_previous_segment =
39330  open_curve_pt->polyline_pt(cs-1)->vertex_coordinate(0);
39331 
39332  unsigned prev_seg_boundary_id =
39333  open_curve_pt->curve_section_pt(cs-1)->boundary_id();
39334 
39335  //Find the error between the initial vertex of the previous
39336  //line and the first vertex of the current line
39337  double error = 0.0;
39338  for(unsigned i=0;i<2;i++)
39339  {
39340  const double dist =
39341  initial_vertex_of_previous_segment[i] -
39342  (*vector_vertex_node.begin())[i];
39343  error += dist*dist;
39344  }
39345  error = sqrt(error); // Reversed only the previous one
39346 
39347  //If the error is bigger than the tolerance then
39348  //we probably need to reverse, but better check
39349  if(error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
39350  {
39351  //Find the error between the final vertex of the previous
39352  //line and the last vertex of the current line
39353  double rev_error = 0.0;
39354  for(unsigned i=0;i<2;i++)
39355  {
39356  const double dist =
39357  initial_vertex_of_previous_segment[i] -
39358  (*--vector_vertex_node.end())[i];
39359  rev_error += dist*dist;
39360  }
39361  rev_error = sqrt(rev_error); // Reversed both the current
39362  // one and the previous one
39363 
39364  if (rev_error >
39365  ToleranceForVertexMismatchInPolygons::Tolerable_error)
39366  {
39367  std::ostringstream error_stream;
39368  error_stream
39369  <<"The distance between the first node of the current\n"
39370  <<"line segment (boundary "<<bound<<") and either end of "
39371  <<"the previous line segment\n"
39372  <<"(boundary "<<prev_seg_boundary_id<<") is bigger than"
39373  << " the desired tolerance " <<
39374  ToleranceForVertexMismatchInPolygons::Tolerable_error<<".\n"
39375  <<"This suggests that the polylines defining the polygonal\n"
39376  <<"representation are not properly ordered.\n"
39377  <<"Fail on last vertex of polyline: ("
39378  <<prev_seg_boundary_id<<") and\nfirst vertex of polyline ("
39379  <<bound<< ").\nThis should have failed when first trying to "
39380  <<"construct the\npolygon.\n";
39381  throw OomphLibError(error_stream.str(),
39382  OOMPH_CURRENT_FUNCTION,
39383  OOMPH_EXCEPTION_LOCATION);
39384  }
39385  else
39386  {
39387  // Reverse both
39388  // Reverse the current vector to line up with the previous one
39389  std::reverse(vector_vertex_node.begin(),
39390  vector_vertex_node.end());
39391  open_curve_pt->polyline_pt(cs-1)->reverse();
39392  }
39393  }
39394  else
39395  {
39396  // Reverse the previous one
39397  open_curve_pt->polyline_pt(cs-1)->reverse();
39398  }
39399 
39400  } // if (cs == 1)
39401  else
39402  {
39403  std::ostringstream error_stream;
39404  error_stream
39405  <<"The distance between the first node of the current\n"
39406  <<"line segment (boundary " << bound << ") and either end of "
39407  <<"the previous line segment\n"
39408  <<"(boundary "<<prev_seg_boundary_id<<") is bigger than the "
39409  <<"desired tolerance " <<
39410  ToleranceForVertexMismatchInPolygons::Tolerable_error << ".\n"
39411  <<"This suggests that the polylines defining the polygonal\n"
39412  <<"representation are not properly ordered.\n"
39413  <<"Fail on last vertex of polyline: ("<<prev_seg_boundary_id
39414  <<") and\nfirst vertex of polyline (" <<bound << ").\n"
39415  <<"This should have failed when first trying to construct\n"
39416  << "the polygon.\n";
39417  throw OomphLibError(error_stream.str(),
39418  OOMPH_CURRENT_FUNCTION,
39419  OOMPH_EXCEPTION_LOCATION);
39420  }
39421  }
39422  else
39423  {
39424  //Reverse the current vector to line up with the previous one
39425  std::reverse(vector_vertex_node.begin(),vector_vertex_node.end());
39426  }
39427 
39428  }
39429 
39430  } // if (cs > 0)
39431 
39432  } // if (!this->is_mesh_distributed())
39433 
39434  // ---------------------------------------------------------------
39435  // Update the polylines representation
39436  // ---------------------------------------------------------------
39437  // Always update the polylines representation, in a distributed
39438  // mesh it is necessary to update the polyline representation since
39439  // it may no longer have vertices (the boundary may not be part of
39440  // the domain in the current processor)
39441 
39442  // The new number of vertices
39443  n_vertex = vector_vertex_node.size();
39444 
39445  // Update the polyline according to the new vertices
39446  TriangleMeshPolyLine *tmp_polyline_pt =
39447  new TriangleMeshPolyLine(vector_vertex_node,bound);
39448 
39449  // Create a temporal "curve section" version of the recently
39450  // created polyline
39451  TriangleMeshCurveSection *tmp_curve_section_pt = tmp_polyline_pt;
39452 
39453  // Tolerance below which the middle point can be deleted (ratio of
39454  // deflection to element length)
39455  double unrefinement_tolerance=
39456  open_curve_pt->polyline_pt(cs)->unrefinement_tolerance();
39457 
39458  // Tolerance to add points
39459  double refinement_tolerance=
39460  open_curve_pt->polyline_pt(cs)->refinement_tolerance();
39461 
39462  // Establish refinement and unrefinement tolerance
39463  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
39464  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
39465 
39466  // Establish the maximum length constraint
39467  double maximum_length = open_curve_pt->polyline_pt(cs)->maximum_length();
39468  tmp_polyline_pt->set_maximum_length(maximum_length);
39469 
39470 #ifdef OOMPH_HAS_MPI
39471  // If the mesh is distributed check that the polyline still has
39472  // vertices
39473  if (this->is_mesh_distributed())
39474  {
39475  if (n_vertex >= 2)
39476  {
39477  // Pass the connection information from the old polyline to
39478  // the new one
39479  this->copy_connection_information(open_curve_pt->polyline_pt(cs),
39480  tmp_curve_section_pt);
39481  } // if (n_vertex >= 2)
39482  } // if (this->is_mesh_distributed())
39483  else
39484 #endif
39485  {
39486  // Pass the connection information from the old polyline to the
39487  // new one
39488  this->copy_connection_information(open_curve_pt->polyline_pt(cs),
39489  tmp_curve_section_pt);
39490  }
39491 
39492  // Now update the polyline according to the new vertices but first
39493  // check if the object is allowed to delete the representation or
39494  // if it should be done by other object
39495  bool delete_it_on_destructor = false;
39496 
39497  std::set<TriangleMeshCurveSection*>::iterator it =
39498  this->Free_curve_section_pt.find(open_curve_pt->curve_section_pt(cs));
39499 
39500  if (it!=this->Free_curve_section_pt.end())
39501  {
39502  this->Free_curve_section_pt.erase(it);
39503  delete open_curve_pt->curve_section_pt(cs);
39504  delete_it_on_destructor = true;
39505  }
39506 
39507  // -------------------------------------------------------------
39508  // Copying the new representation
39509  open_curve_pt->curve_section_pt(cs) = tmp_polyline_pt;
39510 
39511  // Update the Boundary - Polyline map
39512  this->Boundary_curve_section_pt[bound] =
39513  open_curve_pt->curve_section_pt(cs);
39514 
39515  if (delete_it_on_destructor)
39516  {
39517  this->Free_curve_section_pt.insert(open_curve_pt->curve_section_pt(cs));
39518  }
39519 
39520 #ifdef OOMPH_HAS_MPI
39521  // If there are not sub-boundaries mark the boundary if need to be
39522  // trated as shared or as internal boundary
39523  if (this->is_mesh_distributed() && nsub_boundaries == 1)
39524  {
39525  // Clear all previous stored data
39526  this->Boundary_marked_as_shared_boundary[bound].clear();
39527 
39528  // .. and store the flag for the boundary
39529  this->Boundary_marked_as_shared_boundary[bound].push_back(
39530  internal_to_shared_boundary[0]);
39531  }
39532  // --------- Stuff for the sub_boundaries ----- Begin section --------
39533  // Verify if need to deal with sub_boundaries
39534  else if (this->is_mesh_distributed() && nsub_boundaries > 1)
39535  {
39536  // Create temporary representations for the boundaries, only to
39537  // create the mesh when calling Triangle
39538 
39539  // Clear all previous stored data
39540  this->Boundary_subpolylines[bound].clear();
39541  // Now create storage for the sub-boundaries
39542  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
39543 
39544  // Clear all previous stored data
39545  this->Boundary_marked_as_shared_boundary[bound].clear();
39546  // Create storage to mark the internal boundaries as shared
39547  // boundaries
39548  this->Boundary_marked_as_shared_boundary[bound].resize(nsub_boundaries);
39549  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
39550  {
39551  // Now update the polyline according to the sub set of
39552  // vertices, set the chunk number of the polyline
39553  TriangleMeshPolyLine *sub_tmp_polyline_pt =
39554  new TriangleMeshPolyLine(sub_vector_vertex_node[isub], bound, isub);
39555 
39556  // Add the sub-polyline to the container to represent the
39557  // boundary in parts
39558  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
39559 
39560  // Copy the flag that mark the boundary as internal or as
39561  // shared bound
39562  this->Boundary_marked_as_shared_boundary[bound][isub] =
39563  internal_to_shared_boundary[isub];
39564 
39565  // No need to send the unrefinement/refinement and maximum
39566  // length constraints since these are only temporary
39567  // representations
39568 
39569  // But we certanly we need to pass the connection information
39570  // to the sub-polylines
39571  // Get a curve section representation of the sub-polyline
39572  TriangleMeshCurveSection *tmp_sub_curve_section_pt =
39573  sub_tmp_polyline_pt;
39574  this->copy_connection_information_to_sub_polylines(
39575  tmp_curve_section_pt, tmp_sub_curve_section_pt);
39576 
39577  } // for (isub < nsub_boundaries)
39578 
39579  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
39580  // --------- Stuff for the sub_boundaries ----- End section ---------
39581 #endif // OOMPH_HAS_MPI
39582 
39583  // Delete the allocated memory for the geometric object
39584  // that represents the curvilinear boundary
39585  delete mesh_geom_obj_pt;
39586 
39587  } // for (cs < ncurve_section)
39588 
39589  // Cleanup the face mesh
39590  for(unsigned p = 0; p < ncurve_section; p++)
39591  {
39592  face_mesh_pt[p]->flush_node_storage();
39593  delete face_mesh_pt[p];
39594  }
39595 
39596  return update_was_performed;
39597 
39598 }
39599 
39600 #ifdef OOMPH_HAS_MPI
39601 //======================================================================
39602 /// \short Updates the polylines using the elements area as
39603 /// constraint for the number of points along the boundaries
39604 //======================================================================
39605 template <class ELEMENT>
39607 update_shared_curve_using_elements_area(Vector<TriangleMeshPolyLine*>
39608  &vector_polyline_pt,
39609  const Vector<double> &target_areas)
39610 {
39611  // Flag to check if there were a change on the shared boundary
39612  // representation
39613  unsigned update_was_performed = false;
39614 
39615  // Go through all the shared boundaries/polylines
39616  const unsigned n_polylines = vector_polyline_pt.size();
39617  for (unsigned pp = 0; pp < n_polylines; pp++)
39618  {
39619  // Get the boundary id of the current polyline
39620  const unsigned shd_bnd_id = vector_polyline_pt[pp]->boundary_id();
39621 
39622  // Get the chunk number
39623  const unsigned chunk = vector_polyline_pt[pp]->boundary_chunk();
39624 
39625  // Get the face elements that created the shared boundary from the
39626  // bulk shared boundary elements
39627 
39628  // Compute the face elements from the shared boundary elements,
39629  // create an association from the face element with the "bulk"
39630  // elements
39631  std::map<FiniteElement*, FiniteElement*> face_ele_pt_to_bulk_element_pt;
39632 
39633  // The temporary storage for the halo face elements
39634  Vector<FiniteElement*> halo_shared_face_ele_pt;
39635  // The temporary storage for the nonhalo face elements
39636  Vector<FiniteElement*> nonhalo_shared_face_ele_pt;
39637 
39638  // Get the number of shared boundary elements associated with the
39639  // current shared boundary
39640  const unsigned nshared_bound_ele =
39641  this->nshared_boundary_element(shd_bnd_id);
39642 
39643  // Loop over the elements in the shared boundary to create the face
39644  // elements
39645  for (unsigned e = 0; e < nshared_bound_ele; e++)
39646  {
39647  // Get the shared boundary element
39648  FiniteElement* bulk_ele_pt =
39649  this->shared_boundary_element_pt(shd_bnd_id, e);
39650 
39651  // Get the face index
39652  int face_index = this->face_index_at_shared_boundary(shd_bnd_id, e);
39653 
39654  // Before adding the new element we need to ensure that the edge
39655  // that this element represents has not been already added
39656  FiniteElement* face_ele_pt =
39657  new DummyFaceElement<ELEMENT>(bulk_ele_pt, face_index);
39658 
39659  // Establish the association between the bulk element and the
39660  // face element
39661  face_ele_pt_to_bulk_element_pt[face_ele_pt] = bulk_ele_pt;
39662 
39663  // Nonhalo element
39664  if (!bulk_ele_pt->is_halo())
39665  {
39666  // Add nonhalo shared face element to the container
39667  nonhalo_shared_face_ele_pt.push_back(face_ele_pt);
39668  }
39669  else // halo element
39670  {
39671  // Add halo shared face element to the container
39672  halo_shared_face_ele_pt.push_back(face_ele_pt);
39673  }
39674 
39675  } // for (e < nshared_bound_ele)
39676 
39677  // Now we have the face elements, we need to ensure that the halo
39678  // and nonhalo bulk element are sorted one after the other
39679  Vector<Vector<FiniteElement*> > unsorted_shared_bulk_ele_pt;
39680 
39681  // Mark the face elements already used
39682  std::map<FiniteElement*, bool> shared_face_done;
39683 
39684  // Get the number of nonhalo face elements
39685  const unsigned nnonhalo_face_shared_ele =
39686  nonhalo_shared_face_ele_pt.size();
39687 
39688  // Get the number of halo face elements
39689  const unsigned nhalo_face_shared_ele =
39690  halo_shared_face_ele_pt.size();
39691 
39692 #ifdef PARANOID
39693  // The number of nonhalo shared face boundary elements must be the
39694  // half of the total number of shared boundary elements
39695  if (nshared_bound_ele / 2 != nnonhalo_face_shared_ele)
39696  {
39697  std::ostringstream error_message;
39698  error_message
39699  << "The number of shared boundary elements (" << nshared_bound_ele
39700  << ") is not the double\nof the number of unsorted NONHALO shared "
39701  << "face boundary elements (" << nnonhalo_face_shared_ele << ")\n"
39702  << "for the current boundary ("<< shd_bnd_id << ")\n\n";
39703  throw OomphLibError(error_message.str(),
39704  OOMPH_CURRENT_FUNCTION,
39705  OOMPH_EXCEPTION_LOCATION);
39706  }
39707 
39708  // The number of halo shared face boundary elements must be the
39709  // half of the total number of shared boundary elements
39710  if (nshared_bound_ele / 2 != nhalo_face_shared_ele)
39711  {
39712  std::ostringstream error_message;
39713  error_message
39714  << "The number of shared boundary elements (" << nshared_bound_ele
39715  << ") is not the double\nof the number of unsorted HALO shared "
39716  << "face boundary elements (" << nhalo_face_shared_ele << ")\n"
39717  << "for the current boundary ("<< shd_bnd_id << ")\n\n";
39718  throw OomphLibError(error_message.str(),
39719  OOMPH_CURRENT_FUNCTION,
39720  OOMPH_EXCEPTION_LOCATION);
39721  }
39722 #endif
39723 
39724  // ------------------------------------------------------------------
39725  // Loop over the nonhalo face elements and look for the halo face
39726  // element at the other side of the shared boundary
39727  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
39728  {
39729  // Get the inh-th face element
39730  FiniteElement* nonhalo_face_ele_pt = nonhalo_shared_face_ele_pt[inh];
39731 
39732  // Get the number of nodes on the face element
39733  const unsigned nnodes_nh = nonhalo_face_ele_pt->nnode();
39734  // Get the first and last node on the element
39735  Node* nh_first_node_pt = nonhalo_face_ele_pt->node_pt(0);
39736  Node* nh_last_node_pt = nonhalo_face_ele_pt->node_pt(nnodes_nh-1);
39737 
39738  // Now find the (halo) face element at the other side of the
39739  // shared boundary
39740  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
39741  {
39742  // Get the ih-th face element
39743  FiniteElement* halo_face_ele_pt = halo_shared_face_ele_pt[ih];
39744 
39745  // Check that the face element has not been done
39746  if (!shared_face_done[halo_face_ele_pt])
39747  {
39748  // Get the number of nodes on the face element
39749  const unsigned nnodes_h = halo_face_ele_pt->nnode();
39750  // Get the first and last node on the element
39751  Node* h_first_node_pt = halo_face_ele_pt->node_pt(0);
39752  Node* h_last_node_pt = halo_face_ele_pt->node_pt(nnodes_h-1);
39753 
39754  // If the nodes are the same then we have found the (halo)
39755  // face element at the other side of the shared boundary
39756  if (nh_first_node_pt == h_first_node_pt &&
39757  nh_last_node_pt == h_last_node_pt)
39758  {
39759  // Get the BULK elements associated with the face elements
39760  Vector<FiniteElement*> tmp_bulk_element_pt;
39761  // Get the BULK elements associated to the face elements
39762  // (the nonhalo and the halo)
39763  FiniteElement* nonhalo_bulk_ele_pt =
39764  face_ele_pt_to_bulk_element_pt[nonhalo_face_ele_pt];
39765  FiniteElement* halo_bulk_ele_pt =
39766  face_ele_pt_to_bulk_element_pt[halo_face_ele_pt];
39767 
39768  // Add the BULK elements to the temporal storage
39769  tmp_bulk_element_pt.push_back(nonhalo_bulk_ele_pt);
39770  tmp_bulk_element_pt.push_back(halo_bulk_ele_pt);
39771 
39772  // Store the pair of elements associated to the "edge"
39773  unsorted_shared_bulk_ele_pt.push_back(tmp_bulk_element_pt);
39774 
39775  // Mark the face elements as done
39776  shared_face_done[nonhalo_face_ele_pt] = true;
39777  shared_face_done[halo_face_ele_pt] = true;
39778 
39779  // Break the loop for (ih < nhalo_face_shared_ele)
39780  break;
39781  } // if (nh_first_node_pt == h_first_node_pt &&
39782  // nh_last_node_pt == h_last_node_pt)
39783  else if (nh_first_node_pt == h_last_node_pt &&
39784  nh_last_node_pt == h_first_node_pt)
39785  {
39786  // Get the BULK elements associated with the face elements
39787  Vector<FiniteElement*> tmp_bulk_element_pt;
39788  // Get the BULK elements associated to the face elements
39789  // (the nonhalo and the halo)
39790  FiniteElement* nonhalo_bulk_ele_pt =
39791  face_ele_pt_to_bulk_element_pt[nonhalo_face_ele_pt];
39792  FiniteElement* halo_bulk_ele_pt =
39793  face_ele_pt_to_bulk_element_pt[halo_face_ele_pt];
39794 
39795  // Add the BULK elements to the temporal storage
39796  tmp_bulk_element_pt.push_back(nonhalo_bulk_ele_pt);
39797  tmp_bulk_element_pt.push_back(halo_bulk_ele_pt);
39798 
39799  // Store the pair of elements associated to the "edge"
39800  unsorted_shared_bulk_ele_pt.push_back(tmp_bulk_element_pt);
39801 
39802  // Mark the face elements as done
39803  shared_face_done[nonhalo_face_ele_pt] = true;
39804  shared_face_done[halo_face_ele_pt] = true;
39805 
39806  // Break the loop for (ih < nhalo_face_shared_ele)
39807  break;
39808  } // else if (nh_first_node_pt == h_last_node_pt &&
39809  // nh_last_node_pt == h_first_node_pt)
39810 
39811  } // if (face_done[halo_face_ele_pt])
39812 
39813  } // for (ih < nhalo_face_shared_ele)
39814 
39815  } // for (inh < nnonhalo_face_shared_ele)
39816 
39817  // -------------------------------------------------------------
39818  // Now sort the face elements
39819  // -------------------------------------------------------------
39820 
39821  // We already have the shared face elements that make the shared
39822  // boundary (and the bulk elements), now sort them to create a
39823  // contiguous boundary
39824 
39825 #ifdef PARANOID
39826  const unsigned nunsorted_shared_bulk_ele =
39827  unsorted_shared_bulk_ele_pt.size();
39828 
39829  // The number of unsorted shared BULK elements MUST be the same
39830  // as the number of shared_boundary elements divided by two
39831  if (nshared_bound_ele / 2 != nunsorted_shared_bulk_ele)
39832  {
39833  std::ostringstream error_message;
39834  error_message
39835  << "The number of shared boundary elements (" << nshared_bound_ele
39836  << ") is not the double\nof the number of unsorted shared bulk "
39837  << "boundary elements (" << nunsorted_shared_bulk_ele << ")\n"
39838  << "for the current boundary ("<< shd_bnd_id << ")\n\n";
39839  throw OomphLibError(error_message.str(),
39840  OOMPH_CURRENT_FUNCTION,
39841  OOMPH_EXCEPTION_LOCATION);
39842  }
39843 
39844  // The number of done shared face elements MUST be the same as the
39845  // sum of the nonhalo and halo shared boundary face elements
39846  if ((nnonhalo_face_shared_ele + nhalo_face_shared_ele) !=
39847  shared_face_done.size())
39848  {
39849  std::ostringstream error_message;
39850  error_message
39851  << "The number of DONE shared boundary face elements ("
39852  << shared_face_done.size() << ") is not the same\n as the sum of"
39853  << "the nonhalo face shared boundary elements ("
39854  << nnonhalo_face_shared_ele << ")\nand the halo face shared "
39855  << "boundary elements ("<< nhalo_face_shared_ele << ") for the\n/"
39856  << "current boundary (" << shd_bnd_id << ")\n\n";
39857  throw OomphLibError(error_message.str(),
39858  OOMPH_CURRENT_FUNCTION,
39859  OOMPH_EXCEPTION_LOCATION);
39860  }
39861 #endif
39862 
39863  // Clear the already done face elements
39864  shared_face_done.clear();
39865 
39866  // The number of sorted face elements
39867  unsigned nsorted_face_ele = 0;
39868 
39869  // Storing for the sorting nodes extracted from the face
39870  // elements. This are also used to update the polyline
39871  std::list<Node*> sorted_nodes;
39872 
39873  // Storing for the sorted shared face elements
39874  std::list<FiniteElement*> sorted_shared_bound_elements_pt;
39875 
39876  // Get the root face element
39877  FiniteElement* root_face_ele_pt = nonhalo_shared_face_ele_pt[0];
39878  nsorted_face_ele++;
39879 
39880  // Mark face as done
39881  shared_face_done[root_face_ele_pt] = true;
39882 
39883  // The initial and final node on the list
39884  const unsigned nnodes_root = root_face_ele_pt->nnode();
39885  Node *first_node_pt = root_face_ele_pt->node_pt(0);
39886  Node *last_node_pt = root_face_ele_pt->node_pt(nnodes_root-1);
39887 
39888  // Push back on the list the new nodes
39889  sorted_nodes.push_back(first_node_pt);
39890  sorted_nodes.push_back(last_node_pt);
39891 
39892  // Store the bulk elements of the current face
39893  sorted_shared_bound_elements_pt.push_back(
39894  unsorted_shared_bulk_ele_pt[0][0]);
39895  sorted_shared_bound_elements_pt.push_back(
39896  unsorted_shared_bulk_ele_pt[0][1]);
39897 
39898  // Sort the face elements
39899  while (nsorted_face_ele < nnonhalo_face_shared_ele)
39900  {
39901  // Flag to indicate when a node was added
39902  bool node_added = false;
39903 
39904  // Start from the next edge since we have already added the
39905  // previous one as the initial face element
39906  for (unsigned iface = 1; iface < nnonhalo_face_shared_ele; iface++)
39907  {
39908  FiniteElement* tmp_shared_face_ele_pt =
39909  nonhalo_shared_face_ele_pt[iface];
39910 
39911  // If face has not been sorted
39912  if (!shared_face_done[tmp_shared_face_ele_pt])
39913  {
39914  // Get the number of nodes for the current face element
39915  const unsigned tmp_nnodes = tmp_shared_face_ele_pt->nnode();
39916 
39917  // Get each individual node
39918  Node* left_node_pt = tmp_shared_face_ele_pt->node_pt(0);
39919  Node* right_node_pt = tmp_shared_face_ele_pt->node_pt(tmp_nnodes-1);
39920 
39921  if (left_node_pt == first_node_pt)
39922  {
39923  // Push front the new node
39924  sorted_nodes.push_front(right_node_pt);
39925  first_node_pt = right_node_pt;
39926  node_added = true;
39927 
39928  // Store the elements of the current face element
39929  sorted_shared_bound_elements_pt.push_front(
39930  unsorted_shared_bulk_ele_pt[iface][1]);
39931  sorted_shared_bound_elements_pt.push_front(
39932  unsorted_shared_bulk_ele_pt[iface][0]);
39933  }
39934  else if (left_node_pt == last_node_pt)
39935  {
39936  // Push back the new node
39937  sorted_nodes.push_back(right_node_pt);
39938  last_node_pt = right_node_pt;
39939  node_added = true;
39940 
39941  // Store the elements of the current face element
39942  sorted_shared_bound_elements_pt.push_back(
39943  unsorted_shared_bulk_ele_pt[iface][0]);
39944  sorted_shared_bound_elements_pt.push_back(
39945  unsorted_shared_bulk_ele_pt[iface][1]);
39946  }
39947  else if (right_node_pt == first_node_pt)
39948  {
39949  // Push front the new node
39950  sorted_nodes.push_front(left_node_pt);
39951  first_node_pt = left_node_pt;
39952  node_added = true;
39953 
39954  // Store the elements of the current face element
39955  sorted_shared_bound_elements_pt.push_front(
39956  unsorted_shared_bulk_ele_pt[iface][1]);
39957  sorted_shared_bound_elements_pt.push_front(
39958  unsorted_shared_bulk_ele_pt[iface][0]);
39959  }
39960  else if (right_node_pt == last_node_pt)
39961  {
39962  // Push back the new node
39963  sorted_nodes.push_back(left_node_pt);
39964  last_node_pt = left_node_pt;
39965  node_added = true;
39966 
39967  // Store the elements of the current face element
39968  sorted_shared_bound_elements_pt.push_back(
39969  unsorted_shared_bulk_ele_pt[iface][0]);
39970  sorted_shared_bound_elements_pt.push_back(
39971  unsorted_shared_bulk_ele_pt[iface][1]);
39972  }
39973 
39974  if (node_added)
39975  {
39976  // Mark as done if one of its nodes has been added to the
39977  // list
39978  shared_face_done[tmp_shared_face_ele_pt] = true;
39979  nsorted_face_ele++;
39980 
39981  // Break the for
39982  break;
39983  }
39984 
39985  } // if (!shared_face_done[tmp_shared_face_ele_pt])
39986 
39987  } // for (iface < nnonhalo_face_shared_ele)
39988 
39989  } // while (nsorted_face_ele < nnonhalo_face_shared_ele))
39990 
39991  // ----------------------------------------------------------------
39992  // Here we can safely delete the face elements, they are no longer
39993  // required
39994 
39995  // First the nonhalo face elements
39996  for (unsigned inh = 0; inh < nnonhalo_face_shared_ele; inh++)
39997  {
39998  delete nonhalo_shared_face_ele_pt[inh];
39999  nonhalo_shared_face_ele_pt[inh] = 0;
40000  } // for (inh < nnonhalo_face_shared_ele)
40001 
40002  // ... then the halo face elements
40003  for (unsigned ih = 0; ih < nhalo_face_shared_ele; ih++)
40004  {
40005  delete halo_shared_face_ele_pt[ih];
40006  halo_shared_face_ele_pt[ih] = 0;
40007  } // for (inh < nhalo_face_shared_ele)
40008 
40009  // ------------------------------------------------------------------
40010  // At this point we already have a sorted list of nodes, get the
40011  // vertices from them and store them in a vector container
40012 
40013  // Get the number of nodes on the list
40014  const unsigned n_nodes = sorted_nodes.size();
40015 
40016  // The vector to store the vertices
40017  Vector<Vector<double> > polyline_vertices(n_nodes);
40018 
40019  // Copy the vertices from the nodes
40020  unsigned counter = 0;
40021  for (std::list<Node*>::iterator it_nodes = sorted_nodes.begin();
40022  it_nodes != sorted_nodes.end();
40023  it_nodes++)
40024  {
40025  polyline_vertices[counter].resize(2);
40026  polyline_vertices[counter][0] = (*it_nodes)->x(0);
40027  polyline_vertices[counter][1] = (*it_nodes)->x(1);
40028  counter++;
40029  }
40030 
40031  // ------------------------------------------------------------------
40032  // Now get the target areas associated to the shared boundary
40033  // elements
40034 
40035  // Copy the sorted elements in a vector
40036  Vector<FiniteElement*> sorted_shared_ele_pt;
40037  for (std::list<FiniteElement*>::iterator it_ele =
40038  sorted_shared_bound_elements_pt.begin();
40039  it_ele != sorted_shared_bound_elements_pt.end();
40040  it_ele++)
40041  {sorted_shared_ele_pt.push_back((*it_ele));}
40042 
40043  // Get the number of target areas
40044  const unsigned n_shared_target_areas = sorted_shared_ele_pt.size();
40045  Vector<double> sorted_shared_target_areas(n_shared_target_areas);
40046 
40047  // Mark those shared elements already found
40048  std::map<std::pair<GeneralisedElement*, unsigned>, bool> shared_ele_done;
40049 
40050  // Counter for the number of already done shared elements
40051  unsigned count_found_shared_element = 0;
40052 
40053  // Get the target area associated to the shared boundary elements
40054  const unsigned nele = this->nelement();
40055 
40056  // Loop over the elements to find the target areas associated to
40057  // the shared boundary elements
40058  for (unsigned e = 0; e < nele; e++)
40059  {
40060  GeneralisedElement* current_ele_pt = this->element_pt(e);
40061  // Now compare the current element with those in the sorted
40062  // shared element array
40063  for (unsigned s = 0; s < n_shared_target_areas; s++)
40064  {
40065  // Get the element
40066  GeneralisedElement* current_shared_ele_pt = sorted_shared_ele_pt[s];
40067  // Create the pair element-index to check if done
40068  std::pair<GeneralisedElement*, unsigned> pair_gen_ele_idx =
40069  std::make_pair(current_shared_ele_pt, s);
40070  if (!shared_ele_done[pair_gen_ele_idx])
40071  {
40072  // Compare with the global element
40073  if (current_ele_pt == current_shared_ele_pt)
40074  {
40075  // Store the target area of the current shared element
40076  sorted_shared_target_areas[s] = target_areas[e];
40077  // Mark the shared element as done
40078  shared_ele_done[pair_gen_ele_idx] = true;
40079  // Increase the number of found elements
40080  count_found_shared_element++;
40081  } // if (current_ele_pt == current_shared_ele_pt)
40082  } // if (!shared_ele_done[current_shared_ele_pt])
40083  } // for (s < nshared_taget_areas)
40084 
40085  // Check if all shared elements have been found
40086  if (count_found_shared_element == n_shared_target_areas)
40087  {break;}
40088 
40089  } // for (e < nele)
40090 
40091 #ifdef PARANOID
40092  // Check if the number of found target areas is the same as the
40093  // number of shared target areas
40094  if (count_found_shared_element != n_shared_target_areas)
40095  {
40096  std::ostringstream error_message;
40097  error_message
40098  << "The number of found target areas ("
40099  << count_found_shared_element << ") is different from the "
40100  << "total number\nof target areas ("
40101  << n_shared_target_areas << ") in shared boundary ("
40102  << shd_bnd_id <<")\n\n";
40103  throw OomphLibError(error_message.str(),
40104  OOMPH_CURRENT_FUNCTION,
40105  OOMPH_EXCEPTION_LOCATION);
40106  }
40107 #endif
40108 
40109  // The number of vertices
40110  const unsigned n_vertices = n_nodes;
40111 
40112  // Get the number of segments from the input vector_polyline_pt
40113  const unsigned n_segments = vector_polyline_pt[pp]->nsegment();
40114  // Get the number of segments from the input vector_polyline_pt to
40115  // ensure that the shared boundary corresponds to the one
40116  // represented by the shared face elements (this has sence when the
40117  // mesh was re-created from re-starting)
40118 
40119  // Check that the number of vertices correspond with the number of
40120  // segments
40121 #ifdef PARANOID
40122  if (n_segments != n_vertices-1)
40123  {
40124  std::ostringstream error_message;
40125  error_message
40126  << "The number of segments from the current shared polyline "
40127  << "(" << n_segments << ") does not\ncorrespond with the number of "
40128  << "sorted vertices (" << n_vertices-1 << ") of the current shared\n"
40129  << "boundary\n\n";
40130  throw OomphLibError(error_message.str(),
40131  OOMPH_CURRENT_FUNCTION,
40132  OOMPH_EXCEPTION_LOCATION);
40133  }
40134 
40135  // Check that the number of target areas correspond with the number
40136  // of vertices
40137  if (n_segments != n_shared_target_areas/2)
40138  {
40139  std::ostringstream error_message;
40140  error_message
40141  << "The number of segments for the current sorting of edges "
40142  << "(" << n_segments << ") is different\nfrom the number of "
40143  << "target areas (" << n_shared_target_areas/2 << ")\n\n";
40144  throw OomphLibError(error_message.str(),
40145  OOMPH_CURRENT_FUNCTION,
40146  OOMPH_EXCEPTION_LOCATION);
40147  }
40148 #endif
40149 
40150  // ------------------------------------------------------------------
40151  // Get the target areas that are used to perform the unrefinement
40152  // and refinement operation. For each face element on a shared
40153  // polyline there are two bulk elements, a halo and a haloed
40154  // element, each with an associated target area. Review the
40155  // function
40156  // TriangleMesh::create_polylines_from_halo_elements_helper() to
40157  // check how the shared boundaries were created
40158  Vector<double> polyline_target_area(n_segments);
40159  // Loop over the segments in the shared polyline
40160  for (unsigned s = 0; s < n_segments; s++)
40161  {
40162  // Get the minimum of the associated target areas
40163  polyline_target_area[s] = std::min(sorted_shared_target_areas[s*2],
40164  sorted_shared_target_areas[(s*2)+1]);
40165  }
40166 
40167  // Before going to the unrefinement or refinement process check
40168  // that in all processors where the shared boundary lives start
40169  // from the same vertex.
40170  // Start from the bottom left vertex
40171  if (polyline_vertices[n_vertices-1][1] < polyline_vertices[0][1])
40172  {
40173  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
40174  std::reverse(polyline_target_area.begin(), polyline_target_area.end());
40175  }
40176  else if (polyline_vertices[n_vertices-1][1] == polyline_vertices[0][1])
40177  {
40178  if (polyline_vertices[n_vertices-1][0] < polyline_vertices[0][0])
40179  {
40180  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
40181  std::reverse(polyline_target_area.begin(), polyline_target_area.end());
40182  }
40183  }
40184 
40185  // ------------------------------------------------------------------
40186  // Apply unrefinement
40187  bool unrefinement_applied = false;
40188  // Apply unefinement if there are more than three nodes at the
40189  // shared boundary
40190  if (n_vertices > 3)
40191  {
40192  unrefinement_applied =
40193  unrefine_shared_boundary_constrained_by_target_area(
40194  shd_bnd_id, chunk, polyline_vertices, polyline_target_area);
40195  }
40196 
40197  // Apply refinement
40198  bool refinement_applied =
40199  refine_shared_boundary_constrained_by_target_area(polyline_vertices,
40200  polyline_target_area);
40201 
40202  // Was unrefinement/refinement applied
40203  update_was_performed |= (unrefinement_applied || refinement_applied);
40204 
40205  // ------------------------------------------------------------------
40206  // Update the polyline representation of the shared boundary
40207 
40208  // The new shared polyline representation
40209  TriangleMeshPolyLine *new_polyline_pt =
40210  new TriangleMeshPolyLine(polyline_vertices, shd_bnd_id);
40211 
40212  // Get the curve section representation
40213  TriangleMeshCurveSection *curve_section_pt = vector_polyline_pt[pp];
40214 
40215  // Copy the connection information from the old shared polyline to
40216  // the new one
40217  this->copy_connection_information(curve_section_pt, new_polyline_pt);
40218 
40219  // Now update the polyline according to the new vertices but first
40220  // check if the object is allowed to delete the representation or
40221  // if it should be done by other object
40222  bool delete_it_on_destructor = false;
40223 
40224  // Establish the element as being deleted by the destructor of the
40225  // class
40226  std::set<TriangleMeshCurveSection*>::iterator it =
40227  this->Free_curve_section_pt.find(curve_section_pt);
40228 
40229  if (it!=this->Free_curve_section_pt.end())
40230  {
40231  this->Free_curve_section_pt.erase(it);
40232  delete curve_section_pt;
40233  delete_it_on_destructor = true;
40234  }
40235 
40236  // Copy the new representation to the output vector_polyline_pt
40237  vector_polyline_pt[pp] = new_polyline_pt;
40238 
40239  // Get the new curve section representation
40240  TriangleMeshCurveSection *new_curve_section_pt = vector_polyline_pt[pp];
40241 
40242  // Update the Boundary - Polyline map
40243  this->Boundary_curve_section_pt[shd_bnd_id] = new_curve_section_pt;
40244 
40245  if (delete_it_on_destructor)
40246  {
40247  this->Free_curve_section_pt.insert(new_curve_section_pt);
40248  }
40249 
40250  } // for (pp < npoly)
40251 
40252  return update_was_performed;
40253 
40254 }
40255 #endif // #ifdef OOMPH_HAS_MPI
40256 
40257  //=========================================================================
40258  /// \short Helper function that performs the unrefinement process
40259  /// on the specified boundary by using the provided vertices
40260  /// representation and the associated target area.
40261  //=========================================================================
40262  template<class ELEMENT>
40265  const unsigned &c,
40266  Vector<Vector<double> >
40267  &vector_bnd_vertices,
40268  double &unrefinement_tolerance,
40269  Vector<double> &area_constraint)
40270  {
40271  // Store the vertices not allowed for deletion
40272  std::set<Vector<double> > no_delete_vertex;
40273 
40274  // Does the boundary receives connections?
40275  const bool boundary_receive_connections =
40276  this->boundary_connections(b, c, no_delete_vertex);
40277 
40278  // Boolean that indicates whether an actual update of the vertex
40279  // coordinates was performed
40280  bool unrefinement_applied = false;
40281 
40282  // Return inmedately
40283  if (!Do_boundary_unrefinement_constrained_by_target_areas)
40284  {
40285  return unrefinement_applied;
40286  }
40287 
40288  // Strategy to delete nodes: Consider the target area of the
40289  // elements (e_i and e_(i+1)) sharing the i-th node (middle node),
40290  // if the number of segments to be added is equal to zero for both
40291  // elements then compute the average of both target areas and check
40292  // if the number of segments is still zero, if that holds mark the
40293  // node to be deleted. Before delete the node check whether it is in
40294  // the non_delete_vertex list. Skip the i+1-th node and go for the
40295  // (i+2)-th one, it means, increase the counter for current node by
40296  // two.
40297 
40298  // Number of vertices on the boundary
40299  unsigned n_vertex = vector_bnd_vertices.size();
40300 
40301  // Compute a constant value
40302  const double constant_value = 4.0/sqrt(3.0);
40303 
40304  if (n_vertex > 2)
40305  {
40306  // Go through all the vertices and delete points when the target area
40307  // indicates zero points along the boundary
40308  for (unsigned i = 1; i < n_vertex-1; i+=2)
40309  {
40310  if (area_constraint[i-1] > 0 && area_constraint[i] > 0)
40311  {
40312  const double local_zeta_first = vector_bnd_vertices[i-1][0];
40313  const double local_zeta_last = vector_bnd_vertices[i+1][0];
40314  const double local_length_zeta =
40315  std::fabs(local_zeta_last-local_zeta_first);
40316 
40317  const double x1 = vector_bnd_vertices[i-1][1];
40318  const double y1 = vector_bnd_vertices[i-1][2];
40319  const double x2 = vector_bnd_vertices[i+1][1];
40320  const double y2 = vector_bnd_vertices[i+1][2];
40321  const double local_length =
40322  sqrt(((x1-x2)*(x1-x2)) + ((y1-y2)*(y1-y2)));
40323 
40324  const double x_m = vector_bnd_vertices[i][1];
40325  const double y_m = vector_bnd_vertices[i][2];
40326 
40327  const double average_area_constraint =
40328  (area_constraint[i-1] + area_constraint[i]) / 2.0;
40329 
40330  // Compute the length of the the side of an equilateral
40331  // triangle
40332  const double length_side =
40333  sqrt(constant_value*average_area_constraint);
40334 
40335  const double length_side_zeta =
40336  (local_length_zeta * length_side) / local_length;
40337 
40338  // Is the new length greater that the old one
40339  if ((length_side_zeta / local_length_zeta) > 1.0)
40340  {
40341  // If the number of segments is zero then verify the condition for
40342  // deletion of nodes but using the condition in the default
40343  // unrefine_boundary() method. If both conditions are true then
40344  // delete the node
40345  // Maths from http://www.cgafaq.info/wiki/Circle_Through_Three_Points
40346  double a_x=vector_bnd_vertices[i-1][1];
40347  double a_y=vector_bnd_vertices[i-1][2];
40348  double b_x=vector_bnd_vertices[i][1];
40349  double b_y=vector_bnd_vertices[i][2];
40350  double c_x=vector_bnd_vertices[i+1][1];
40351  double c_y=vector_bnd_vertices[i+1][2];
40352 
40353  double a=b_x-a_x;
40354  double b=b_y-a_y;
40355  double c=c_x-a_x;
40356  double d=c_y-a_y;
40357 
40358  double e=a*(a_x+b_x)+b*(a_y+b_y);
40359  double f=c*(a_x+c_x)+d*(a_y+c_y);
40360 
40361  double g=2.0*(a*(c_y-b_y)-b*(c_x-b_x));
40362 
40363  bool do_it=false;
40364  if (std::fabs(g)<1.0e-14)
40365  {
40366  do_it=true;
40367  }
40368  else
40369  {
40370  double p_x=(d*e-b*f)/g;
40371  double p_y=(a*f-c*e)/g;
40372 
40373  double r=sqrt(pow((a_x-p_x),2)+pow((a_y-p_y),2));
40374 
40375  double rhalfca_x=0.5*(a_x-c_x);
40376  double rhalfca_y=0.5*(a_y-c_y);
40377 
40378  double halfca_squared=pow(rhalfca_x,2)+pow(rhalfca_y,2);
40379 
40380  double sticky_out_bit=r-sqrt(std::fabs((r*r) - halfca_squared));
40381 
40382  // If sticky out bit divided by distance between end nodes
40383  // is less than tolerance the boundary is so flat that we
40384  // can safely kill the node
40385  if ((sticky_out_bit/(2.0*sqrt(halfca_squared)))<
40386  unrefinement_tolerance)
40387  {
40388  do_it=true;
40389  }
40390  }
40391 
40392  // If the vertex was proposed for deletion check if it is
40393  // allowed for being deleted
40394  if (do_it && boundary_receive_connections)
40395  {
40396  // Is the vertex one of the non deletable vertices
40397  for (std::set<Vector<double> >::iterator it =
40398  no_delete_vertex.begin();
40399  it != no_delete_vertex.end(); it++)
40400  {
40401  // Compute the distance between the proposed node to
40402  // delete and the ones that should not be deleted
40403  const double x = (*it)[0];
40404  const double y = (*it)[1];
40405  double error = (x_m - x)*(x_m - x) + (y_m - y)*(y_m - y);
40406  error = sqrt(error);
40407 
40408  if(error <
40409  ToleranceForVertexMismatchInPolygons::Tolerable_error)
40410  {
40411  // Do not delete the vertex
40412  do_it = false;
40413  break;
40414  }
40415 
40416  }
40417 
40418  } // if (do_it && boundary_receive_connections)
40419 
40420  // Remove node?
40421  if (do_it)
40422  {
40423  vector_bnd_vertices[i].resize(0);
40424  }
40425  } // if (n_seg == 0)
40426  } // if (area_constraint[i] >= 0)
40427  } // for (i < n_vertex-1)
40428 
40429  // Create a new (temporary) vector for the nodes, so that deleted nodes
40430  // are not stored
40431  Vector<Vector<double> > compact_vector;
40432 
40433  // Compact vector for target areas too
40434  Vector<double> compact_area_constraint;
40435 
40436  // Copy only the non deleted nodes
40437  for(unsigned i = 0; i < n_vertex; i++)
40438  {
40439  // If the entry was not deleted include it in the new vector
40440  if (vector_bnd_vertices[i].size()!=0)
40441  {
40442  compact_vector.push_back(vector_bnd_vertices[i]);
40443  }
40444  }
40445 
40446  // ------------------------------------------------------------------
40447  // Size of the target areas vector
40448  unsigned nsize_target = area_constraint.size();
40449  if (nsize_target == 1)
40450  {
40451  // No node was deleted, just copy the target area
40452  compact_area_constraint.push_back(area_constraint[0]);
40453  }
40454 
40455  // Copy the target areas
40456  for(unsigned i = 1; i < n_vertex; i+=2)
40457  {
40458  // If the entry was not deleted include the target areas of both
40459  // elements sharing the node
40460  if (vector_bnd_vertices[i].size()!=0)
40461  {
40462  compact_area_constraint.push_back(area_constraint[i-1]);
40463  // To catch the case when working with even number of vertex
40464  if (i < nsize_target)
40465  {
40466  compact_area_constraint.push_back(area_constraint[i]);
40467  }
40468  }
40469  else
40470  {
40471  // If the node was deleted then compute the new target area as the
40472  // average of the target area of the elements sharing the node
40473  double new_area_constraint =
40474  (area_constraint[i-1] + area_constraint[i]) / 2.0;
40475  compact_area_constraint.push_back(new_area_constraint);
40476  }
40477  }
40478 
40479  // If the size of the compact vector is different from the size of the
40480  // vector before applying the area length constraint then the polyline
40481  // was updated
40482  if( n_vertex != compact_vector.size() )
40483  {
40484  unrefinement_applied = true;
40485  }
40486 
40487  // Copy back to the original vector
40488  n_vertex = compact_vector.size();
40489  vector_bnd_vertices.resize(n_vertex);
40490  for(unsigned i = 0; i < n_vertex; i++)
40491  {
40492  vector_bnd_vertices[i].resize(3);
40493  vector_bnd_vertices[i][0] = compact_vector[i][0];
40494  vector_bnd_vertices[i][1] = compact_vector[i][1];
40495  vector_bnd_vertices[i][2] = compact_vector[i][2];
40496  }
40497 
40498  // Copy back to the original vector of target areas
40499  unsigned ntarget_areas = compact_area_constraint.size();
40500  area_constraint.resize(ntarget_areas);
40501  for(unsigned i = 0; i < ntarget_areas; i++)
40502  {
40503  area_constraint[i] = compact_area_constraint[i];
40504  }
40505 
40506  } // if (n_vertex > 2)
40507 
40508  return unrefinement_applied;
40509 
40510  }
40511 
40512  //=========================================================================
40513  /// \short Helper function that performs the refinement process
40514  /// on the specified boundary by using the provided vertices
40515  /// representation and the associated elements target area.
40516  //=========================================================================
40517  template<class ELEMENT>
40520  mesh_geom_obj_pt,
40521  Vector<Vector<double> >
40522  &vector_bnd_vertices,
40523  double &refinement_tolerance,
40524  Vector<double> &area_constraint)
40525  {
40526  // Boolean that indicates whether an actual update of the vertex
40527  // coordinates was performed
40528  bool refinement_applied = false;
40529 
40530  // Return inmedately
40531  if (!Do_boundary_refinement_constrained_by_target_areas)
40532  {
40533  return refinement_applied;
40534  }
40535 
40536  // Get the total number of current vertices
40537  unsigned n_vertex=vector_bnd_vertices.size();
40538 
40539  // Compute a constant value
40540  const double constant_value = 4.0/sqrt(3.0);
40541 
40542  if (n_vertex > 1)
40543  {
40544  // Create a new (temporary) vector for the nodes, so that new
40545  // nodes can be stored
40546  Vector<Vector<double> > new_vector;
40547 
40548  // Go through all the vertices and create points according to the
40549  // specified element area
40550  for (unsigned i = 0; i < n_vertex-1; i++)
40551  {
40552  // Include the first node
40553  new_vector.push_back(vector_bnd_vertices[i]);
40554 
40555  if (area_constraint[i] > 0)
40556  {
40557  double local_zeta_first = vector_bnd_vertices[i][0];
40558  double local_zeta_last = vector_bnd_vertices[i+1][0];
40559  const double local_length_zeta =
40560  std::fabs(local_zeta_last-local_zeta_first);
40561 
40562  // Check if need to interchange the zeta first and the zeta
40563  // last (to ensure the same order in zeta values in any two
40564  // processors)
40565  if (local_zeta_first > local_zeta_last)
40566  {
40567  const double tmp_zeta = local_zeta_first;
40568  local_zeta_first = local_zeta_last;
40569  local_zeta_last = tmp_zeta;
40570  }
40571 
40572  const double x1 = vector_bnd_vertices[i][1];
40573  const double y1 = vector_bnd_vertices[i][2];
40574  const double x2 = vector_bnd_vertices[i+1][1];
40575  const double y2 = vector_bnd_vertices[i+1][2];
40576  const double local_length =
40577  sqrt(((x1-x2)*(x1-x2)) + ((y1-y2)*(y1-y2)));
40578 
40579  // Compute the length in zeta units
40580  const double length_side = sqrt(constant_value*area_constraint[i]);
40581  const double length_side_zeta =
40582  (local_length_zeta * length_side) / local_length;
40583 
40584  // How many segments should be introduced
40585  const double n_seg_double = length_side_zeta/local_length_zeta;
40586 
40587  // One segment initialy (the original one)
40588  unsigned n_seg = 1;
40589 
40590  // How many more segments to introduce?
40591  n_seg+=static_cast<unsigned>(std::floor(1.0/n_seg_double));
40592 
40593  // Are there segments to introduce? There must be at least one
40594  // segment, the original one
40595  if (n_seg > 0)
40596  {
40597  // The zeta increment
40598  double zeta_increment = (local_length_zeta)/((double)n_seg);
40599 
40600  Vector<double> zeta(1);
40601  // Create the n_seg segmets between each pair of nodes
40602  for(unsigned s=1;s<n_seg;s++)
40603  {
40604  // Get the coordinates
40605  zeta[0]= local_zeta_first + zeta_increment*double(s);
40606  Vector<double> vertex(2);
40607  mesh_geom_obj_pt->position(zeta, vertex);
40608 
40609  // Create the new node
40610  Vector<double> new_node(3);
40611  new_node[0]=zeta[0];
40612  new_node[1]=vertex[0];
40613  new_node[2]=vertex[1];
40614 
40615  // Include the new node
40616  new_vector.push_back(new_node);
40617 
40618  } // for (s<=n_seg)
40619 
40620  } // if (n_seg > 0)
40621 
40622  } // if (area_constraint[i] >= 0)
40623 
40624  } // for (i < n_vertex-1)
40625 
40626  // Once finished all the vertices add the last node to the vector
40627  new_vector.push_back(vector_bnd_vertices[n_vertex-1]);
40628 
40629  // If the new size of the vector (including the added nodes) is
40630  // different from the size of the vector before applying the
40631  // area length constraint then the polyline was updated
40632  n_vertex=new_vector.size();
40633  if( n_vertex != vector_bnd_vertices.size() )
40634  {
40635  refinement_applied = true;
40636  }
40637 
40638  // Copy the new representation
40639  vector_bnd_vertices.resize(n_vertex);
40640  for(unsigned i=0;i<n_vertex;i++)
40641  {
40642  vector_bnd_vertices[i].resize(3);
40643  vector_bnd_vertices[i][0]=new_vector[i][0];
40644  vector_bnd_vertices[i][1]=new_vector[i][1];
40645  vector_bnd_vertices[i][2]=new_vector[i][2];
40646  }
40647 
40648  } // if (n_vertex > 1)
40649 
40650  return refinement_applied;
40651 
40652  }
40653 
40654  //======================================================================
40655  /// \short Helper function that performs the unrefinement process
40656  /// on the specified boundary by using the provided vertices
40657  /// representation and the associated target area.
40658  /// NOTE: This is the version that applies unrefinement to shared
40659  /// boundaries
40660  //======================================================================
40661  template <class ELEMENT>
40664  const unsigned &b,
40665  const unsigned &c,
40666  Vector<Vector<double> > &vector_bnd_vertices,
40667  Vector<double> &area_constraint)
40668  {
40669  // Store the vertices not allowed for deletion
40670  std::set<Vector<double> > no_delete_vertex;
40671 
40672  // Does the boundary receives connections?
40673  const bool boundary_receive_connections =
40674  this->boundary_connections(b, c, no_delete_vertex);
40675 
40676  // Boolean that indicates whether an actual update of the vertex
40677  // coordinates was performed
40678  bool unrefinement_applied = false;
40679 
40680  // Return inmedately
40681  if (!Do_shared_boundary_unrefinement_constrained_by_target_areas)
40682  {
40683  return unrefinement_applied;
40684  }
40685 
40686  // Strategy to delete nodes:
40687 
40688  // Strategy to delete nodes: Consider the target area of the
40689  // elements (e_i and e_(i+1)) sharing the i-th node (middle node),
40690  // if the number of segments to be added is equal to zero for both
40691  // elements then compute the average of both target areas and check
40692  // if the number of segments is still zero, if that holds mark the
40693  // node to be deleted. Before delete the node check whether it is in
40694  // the non_delete_vertex list. Skip the i+1-th node and go for the
40695  // (i+2)-th one, it means, increase the counter for current node by
40696  // two.
40697 
40698  // Number of vertices on the boundary
40699  unsigned n_vertex = vector_bnd_vertices.size();
40700 
40701  // Compute a constant value
40702  const double constant_value = 4.0/sqrt(3.0);
40703 
40704  if (n_vertex > 2)
40705  {
40706  // Go through all the vertices and delete points when the target
40707  // area indicates zero points along the boundary
40708  for (unsigned i = 1; i < n_vertex-1; i+=2)
40709  {
40710  // Is a target area assigned to the left and right element of
40711  // the i-th node
40712  if (area_constraint[i-1] > 0 && area_constraint[i] > 0)
40713  {
40714  // Get the vertices to the left
40715  const double x1 = vector_bnd_vertices[i-1][0];
40716  const double y1 = vector_bnd_vertices[i-1][1];
40717  // ... and to the right of the i-th vertex
40718  const double x2 = vector_bnd_vertices[i+1][0];
40719  const double y2 = vector_bnd_vertices[i+1][1];
40720 
40721  // The distance
40722  const double local_length =
40723  sqrt(((x1-x2)*(x1-x2)) + ((y1-y2)*(y1-y2)));
40724 
40725  // Get the middle vertex
40726  const double x_m = vector_bnd_vertices[i][0];
40727  const double y_m = vector_bnd_vertices[i][1];
40728 
40729  // The average area
40730  const double average_area_constraint =
40731  (area_constraint[i-1] + area_constraint[i]) / 2.0;
40732 
40733  // Compute the base length of the triangle with
40734  // area_constraint area
40735  const double length_side =
40736  sqrt(constant_value*average_area_constraint);
40737 
40738  // Is the new length greater than the old one
40739  if ((length_side / local_length) > 1.0)
40740  {
40741  bool do_it=true;
40742 
40743  // If the vertex was proposed for deletion check that it is
40744  // allowed for being deleted
40745  if (do_it && boundary_receive_connections)
40746  {
40747  // Is the vertex one of the non deletable vertices
40748  for (std::set<Vector<double> >::iterator it =
40749  no_delete_vertex.begin();
40750  it != no_delete_vertex.end(); it++)
40751  {
40752  // Compute the distance between the proposed node to delete
40753  // and the ones that should not be deleted
40754  const double x = (*it)[0];
40755  const double y = (*it)[1];
40756  double error = (x_m - x)*(x_m - x) + (y_m - y)*(y_m - y);
40757  error = sqrt(error);
40758 
40759  if(error <
40760  ToleranceForVertexMismatchInPolygons::Tolerable_error)
40761  {
40762  // Do not delete the vertex
40763  do_it = false;
40764  break;
40765  }
40766 
40767  }
40768 
40769  } // if (do_it && boundary_receive_connections)
40770 
40771  // Remove node?
40772  if (do_it)
40773  {
40774  vector_bnd_vertices[i].resize(0);
40775  }
40776  } // if ((local_length / length_side) <= 1.3)
40777 
40778  } // if (area_constraint[i] >= 0)
40779 
40780  } // for (i < n_vertex-1)
40781 
40782  // Create a new (temporary) vector for the nodes, so that deleted nodes
40783  // are not stored
40784  Vector<Vector<double> > compact_vector;
40785 
40786  // Compact vector for target areas too
40787  Vector<double> compact_area_constraint;
40788 
40789  // Copy only the non deleted nodes
40790  for(unsigned i = 0; i < n_vertex; i++)
40791  {
40792  // If the entry was not deleted include it in the new vector
40793  if (vector_bnd_vertices[i].size()!=0)
40794  {
40795  compact_vector.push_back(vector_bnd_vertices[i]);
40796  }
40797  }
40798 
40799  // ------------------------------------------------------------------
40800  // The number of target areas
40801  unsigned n_area_constraint = area_constraint.size();
40802  if (n_area_constraint == 1)
40803  {
40804  // No node could be deleted then just copy the target area
40805  compact_area_constraint.push_back(area_constraint[0]);
40806  }
40807 
40808  // Copy the target areas
40809  for(unsigned i = 1; i < n_vertex; i+=2)
40810  {
40811  // If the entry was not deleted include the target areas of both
40812  // elements sharing the node
40813  if (vector_bnd_vertices[i].size()!=0)
40814  {
40815  compact_area_constraint.push_back(area_constraint[i-1]);
40816  // To catch the case when working with even number of vertices
40817  if (i < n_area_constraint)
40818  {
40819  compact_area_constraint.push_back(area_constraint[i]);
40820  }
40821  }
40822  else
40823  {
40824  // If the node was deleted then compute the new target area as the
40825  // average of the target area of the elements sharing the node
40826  const double new_area_constraint =
40827  (area_constraint[i-1] + area_constraint[i]) / 2.0;
40828  compact_area_constraint.push_back(new_area_constraint);
40829  }
40830  } // for (i < n_vertex)
40831 
40832  // If the size of the compact vector is different from the size of
40833  // the vector before applying the area length constraint then the
40834  // polyline was updated
40835  if( n_vertex != compact_vector.size() )
40836  {
40837  unrefinement_applied = true;
40838  }
40839 
40840  // Copy back to the original vector
40841  n_vertex = compact_vector.size();
40842  vector_bnd_vertices.resize(n_vertex);
40843  for(unsigned i = 0; i < n_vertex; i++)
40844  {
40845  vector_bnd_vertices[i].resize(2);
40846  vector_bnd_vertices[i][0] = compact_vector[i][0];
40847  vector_bnd_vertices[i][1] = compact_vector[i][1];
40848  }
40849 
40850  // Copy back to the original vector of target areas
40851  unsigned ntarget_areas = compact_area_constraint.size();
40852  area_constraint.resize(ntarget_areas);
40853  for(unsigned i = 0; i < ntarget_areas; i++)
40854  {
40855  area_constraint[i] = compact_area_constraint[i];
40856  }
40857 
40858  } // if (n_vertex > 2)
40859 
40860  return unrefinement_applied;
40861 
40862  }
40863 
40864  //======================================================================
40865  /// \short Helper function that performs the refinement process
40866  /// on the specified boundary by using the provided vertices
40867  /// representation and the associated elements target area.
40868  /// NOTE: This is the version that applies refinement to shared
40869  /// boundaries
40870  //======================================================================
40871  template <class ELEMENT>
40874  Vector<Vector<double> > &vector_bnd_vertices,
40875  Vector<double> &area_constraint)
40876  {
40877  // Boolean that indicates whether an actual update of the vertex
40878  // coordinates was performed
40879  bool refinement_applied = false;
40880 
40881  // Return inmedately
40882  if (!Do_shared_boundary_refinement_constrained_by_target_areas)
40883  {
40884  return refinement_applied;
40885  }
40886 
40887  // Get the number of segments
40888  unsigned nsegments = vector_bnd_vertices.size() - 1;
40889 
40890  // Create a new (temporary) vector for the nodes, so that new nodes
40891  // can be stored
40892  Vector<Vector<double> > tmp_bnd_vertices;
40893 
40894  // Compute a constant value
40895  const double constant_value = 4.0/sqrt(3.0);
40896 
40897  for (unsigned s = 0; s < nsegments; s++)
40898  {
40899  Vector<double> left_vertex = vector_bnd_vertices[s];
40900  Vector<double> right_vertex = vector_bnd_vertices[s+1];
40901 
40902  // Initial and final point of the segment
40903  const double x1 = left_vertex[0];
40904  const double y1 = left_vertex[1];
40905  const double x2 = right_vertex[0];
40906  const double y2 = right_vertex[1];
40907 
40908  // Lenght of the segment
40909  const double segment_length =
40910  sqrt(((x1-x2)*(x1-x2))+((y1-y2)*(y1-y2)));
40911 
40912  // Compute the distance for the new segments
40913  const double new_segment_length =
40914  sqrt(constant_value*area_constraint[s]);
40915 
40916  // How many segments should be introduced
40917  const double n_seg_double = new_segment_length / segment_length;
40918 
40919  // One segment initialy (the original one)
40920  unsigned nseg = 1;
40921  // How many more segments to introduce?
40922  nseg+=static_cast<unsigned>(std::floor(1.0/n_seg_double));
40923 
40924  // The left vertex must be always included, even though no new vertex
40925  // be added
40926  tmp_bnd_vertices.push_back(left_vertex);
40927 
40928  // Are there segments to introduce? There must be at least one
40929  // segment, the original one
40930  if (nseg > 0)
40931  {
40932  // Create intermediate vertices
40933  double incrementx = (right_vertex[0] - left_vertex[0])/(double)(nseg);
40934  double incrementy = (right_vertex[1] - left_vertex[1])/(double)(nseg);
40935  for (unsigned i = 1; i < nseg; i++)
40936  {
40937  Vector<double> tmp_vertex(2);
40938  tmp_vertex[0] = left_vertex[0] + incrementx*i;
40939  tmp_vertex[1] = left_vertex[1] + incrementy*i;
40940  tmp_bnd_vertices.push_back(tmp_vertex);
40941  } // for (i < nseg)
40942 
40943  } // if (nseg > 0)
40944 
40945  } // for (s < nsegments)
40946 
40947  // Add the last vertex
40948  tmp_bnd_vertices.push_back(vector_bnd_vertices[nsegments]);
40949 
40950  // If the new size of the vector (including the added nodes) is
40951  // different from the size of the vector before applying the
40952  // refinement then the polyline was updated
40953  nsegments = tmp_bnd_vertices.size() - 1;
40954  if( nsegments != vector_bnd_vertices.size() - 1 )
40955  {
40956  refinement_applied = true;
40957 
40958  // Copy across
40959  vector_bnd_vertices.resize(nsegments + 1);
40960  for(unsigned i = 0; i < nsegments + 1; i++)
40961  {
40962  vector_bnd_vertices[i].resize(2);
40963  vector_bnd_vertices[i][0] = tmp_bnd_vertices[i][0];
40964  vector_bnd_vertices[i][1] = tmp_bnd_vertices[i][1];
40965  }
40966  }
40967 
40968  return refinement_applied;
40969 
40970  }
40971 
40972 //======================================================================
40973 /// \short Updates the polylines representation after restart
40974 //======================================================================
40975 template <class ELEMENT>
40977 update_polygon_after_restart(TriangleMeshPolygon* &polygon_pt)
40978 {
40979 
40980  // **********************************************************************
40981  // 1) Collect the elements adjacet to the polyline boundary id and
40982  // update the polyline
40983  // **********************************************************************
40984 
40985  // (1.1) Get the face mesh representation
40986  Vector<Mesh*> face_mesh_pt;
40987  get_face_mesh_representation(polygon_pt,face_mesh_pt);
40988 
40989  // (1.2) Create vertices of the polylines by using the vertices of the
40990  // FaceElements
40991  Vector<double> vertex_coord(3); // zeta,x,y
40992  Vector<double> bound_left(1);
40993  Vector<double> bound_right(1);
40994 
40995  const unsigned n_polyline = polygon_pt->npolyline();
40996 
40997  // Go for each polyline
40998  for(unsigned p=0;p<n_polyline;p++)
40999  {
41000  // Get the MeshAsGeomObject representation just once per polyline,
41001  // this object is only used by the
41002  // refine_boundary_constrained_by_target_area() method. We get it here
41003  // to ensure that all processors (in a distributed context) get this
41004  // representation just once, and because an AllToAll MPI communication
41005  // is used in this calling
41006  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt[p]);
41007 
41008  // Set of coordinates that are on the boundary
41009  // Set entries are ordered on first entry in vector which stores
41010  // the boundary coordinate so the vertices come out in order!
41011  std::set<Vector<double> > vertex_nodes;
41012 
41013  // Vector to store the vertices, transfer the sorted vertices from the
41014  // set to this vector, --- including the z-value ---
41015  Vector<Vector<double> > tmp_vector_vertex_node;
41016 
41017  // Vector to store the coordinates of the polylines, same as the
41018  // tmp_vector_vertex_node vector (after adding more nodes) but
41019  // --- without the z-value ---, used to re-generate the polylines
41020  Vector<Vector<double> > vector_vertex_node;
41021 
41022 #ifdef OOMPH_HAS_MPI
41023  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
41024  // Set of coordinates that are on the boundary (splitted boundary version)
41025  // The first vector is used to allocate the points for each sub-boundary
41026  // Set entries are ordered on first entry in vector which stores
41027  // the boundary coordinate so the vertices come out in order!
41028  Vector<std::set<Vector<double> > >sub_vertex_nodes;
41029 
41030  // Vector to store the vertices, transfer the sorted vertices from the
41031  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
41032  Vector<Vector<Vector<double> > >sub_tmp_vector_vertex_node;
41033 
41034  // Vector to store the coordinates of the polylines that will represent
41035  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
41036  // but --- without the z-value ---, used to generate the sub-polylines
41037  Vector<Vector<Vector<double> > > sub_vector_vertex_node;
41038  // --------- Stuff to deal with splitted boundaries ----------- End ------
41039 #endif
41040 
41041  //Get the boundary id
41042  unsigned bound=polygon_pt->curve_section_pt(p)->boundary_id();
41043 
41044  /// Use a vector of vector for vertices and target areas to
41045  /// deal with the cases when the boundaries are split by the
41046  /// distribution process
41047 
41048  // Loop over the face elements (ordered) and add their vertices
41049  const unsigned nface_element = face_mesh_pt[p]->nelement();
41050 
41051  // Store the non halo face elements, the ones from which we will
41052  // get the vertices
41053  Vector<FiniteElement*> non_halo_face_element_pt;
41054  // Map to store the index of the face element on a boundary
41055  std::map<FiniteElement*,unsigned> face_element_index_on_boundary;
41056 
41057  for(unsigned ef=0;ef<nface_element;++ef)
41058  {
41059  FiniteElement* ele_face_pt = face_mesh_pt[p]->finite_element_pt(ef);
41060  // Skip the halo elements
41061 #ifdef OOMPH_HAS_MPI
41062  if (this->is_mesh_distributed())
41063  {
41064  // Only work with non-halo elements
41065  if (ele_face_pt->is_halo()) {continue;}
41066  }
41067 #endif
41068  // Add the face element to the vector
41069  non_halo_face_element_pt.push_back(ele_face_pt);
41070  face_element_index_on_boundary[ele_face_pt] = ef;
41071  }
41072 
41073  // Get the number of non halo face element
41074  const unsigned nnon_halo_face_element = non_halo_face_element_pt.size();
41075 
41076  // Map to know the already sorted face elements
41077  std::map<FiniteElement*,bool> face_element_done;
41078 
41079  // Number of done face elements
41080  unsigned nsorted_face_elements = 0;
41081 
41082 #ifdef OOMPH_HAS_MPI
41083  // Counter for sub_boundaries
41084  unsigned nsub_boundaries = 0;
41085 #endif // #ifdef OOMPH_HAS_MPI
41086 
41087  // Continue until all the face elements have been sorted
41088  // This while is to deal with the cases of splitted boundaries
41089  while(nsorted_face_elements < nnon_halo_face_element)
41090  {
41091  // Get and initial face element
41092  FiniteElement* ele_face_pt = 0;
41093 #ifdef PARANOID
41094  bool found_initial_face_element = false;
41095 #endif
41096 
41097  unsigned iface = 0;
41098  for (iface = 0; iface < nnon_halo_face_element; iface++)
41099  {
41100  ele_face_pt = non_halo_face_element_pt[iface];
41101  // If not done then take it as initial face element
41102  if (!face_element_done[ele_face_pt])
41103  {
41104 #ifdef PARANOID
41105  found_initial_face_element = true;
41106 #endif
41107  nsorted_face_elements++;
41108  iface++;
41109  break;
41110  }
41111  }
41112 
41113 #ifdef PARANOID
41114  if (!found_initial_face_element)
41115  {
41116  std::ostringstream error_message;
41117  error_message
41118  <<"Could not find an initial face element for the current segment\n";
41119  // << "----- Possible memory leak -----\n";
41120  throw OomphLibError(error_message.str(),
41121  "RefineableTriangleMesh::update_polygon_after_restart()",
41122  OOMPH_EXCEPTION_LOCATION);
41123  }
41124 #endif
41125 
41126  // Local set of coordinates that are on the boundary
41127  // Set entries are ordered on first entry in vector which stores
41128  // the boundary coordinate so the vertices come out in order!
41129  std::set<Vector<double> > local_vertex_nodes;
41130 
41131  // Vector to store the vertices, transfer the sorted vertices from the
41132  // set (local) to this vector (local), --- including the z-value ---
41133  Vector<Vector<double> > local_tmp_vector_vertex_node;
41134 
41135  // ------------------------------------------------------------------
41136  // ------------------------------------------------------------------
41137  // -----------------------------------------------------------------
41138  // Add the vertices of the initial face element to the set of local
41139  // sorted vertices
41140  // -----------------------------------------------------------------
41141  unsigned nnode = ele_face_pt->nnode();
41142  // Add the left-hand node to the set:
41143  // Boundary coordinate
41144  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound,bound_left);
41145  vertex_coord[0] = bound_left[0];
41146 
41147  // Actual coordinates
41148  for(unsigned i=0;i<2;i++)
41149  {
41150  vertex_coord[i+1] = ele_face_pt->node_pt(0)->x(i);
41151  }
41152  local_vertex_nodes.insert(vertex_coord);
41153 
41154  // Add the right-hand nodes to the set:
41155  // Boundary coordinate
41156  ele_face_pt->node_pt(nnode-1)->
41157  get_coordinates_on_boundary(bound,bound_right);
41158  vertex_coord[0] = bound_right[0];
41159 
41160  // Actual coordinates
41161  for(unsigned i=0;i<2;i++)
41162  {
41163  vertex_coord[i+1] = ele_face_pt->node_pt(nnode-1)->x(i);
41164  }
41165  local_vertex_nodes.insert(vertex_coord);
41166 
41167  // The initial and final node on the set
41168  Node *first_node_pt = ele_face_pt->node_pt(0);
41169  Node *last_node_pt = ele_face_pt->node_pt(nnode-1);
41170 
41171  // Mark the current face element as done
41172  face_element_done[ele_face_pt] = true;
41173 
41174  // ------------------------------------------------------------------
41175  // ------------------------------------------------------------------
41176  // ------------------------------------------------------------------
41177 
41178  // Continue iterating if a new face element has been added to the
41179  // list
41180  bool face_element_added = false;
41181 
41182  // While a new face element has been added to the set of sorted
41183  // face elements then re-iterate
41184  do
41185  {
41186  // Start from the next face elements since we have already added
41187  // the previous one as the initial face element (any previous face
41188  // element had to be added on previous iterations)
41189  for (unsigned iiface=iface;iiface<nnon_halo_face_element;iiface++)
41190  {
41191  face_element_added = false;
41192  ele_face_pt = non_halo_face_element_pt[iiface];
41193  if (!face_element_done[ele_face_pt])
41194  {
41195  // Get each individual node to check if they are contiguous
41196  nnode = ele_face_pt->nnode();
41197  Node* left_node_pt = ele_face_pt->node_pt(0);
41198  Node* right_node_pt = ele_face_pt->node_pt(nnode-1);
41199 
41200  if (left_node_pt == first_node_pt)
41201  {
41202  first_node_pt = right_node_pt;
41203  face_element_added = true;
41204  }
41205  else if (left_node_pt == last_node_pt)
41206  {
41207  last_node_pt = right_node_pt;
41208  face_element_added = true;
41209  }
41210  else if (right_node_pt == first_node_pt)
41211  {
41212  first_node_pt = left_node_pt;
41213  face_element_added = true;
41214  }
41215  else if (right_node_pt == last_node_pt)
41216  {
41217  last_node_pt = left_node_pt;
41218  face_element_added = true;
41219  }
41220 
41221  if (face_element_added)
41222  {
41223  // Add the left-hand node to the set:
41224  // Boundary coordinate
41225  left_node_pt->get_coordinates_on_boundary(bound,bound_left);
41226  vertex_coord[0] = bound_left[0];
41227 
41228  // Actual coordinates
41229  for(unsigned i=0;i<2;i++)
41230  {
41231  vertex_coord[i+1] = left_node_pt->x(i);
41232  }
41233  local_vertex_nodes.insert(vertex_coord);
41234 
41235  // Add the right-hand nodes to the set:
41236  // Boundary coordinate
41237  right_node_pt->get_coordinates_on_boundary(bound,bound_right);
41238  vertex_coord[0] = bound_right[0];
41239 
41240  // Actual coordinates
41241  for(unsigned i=0;i<2;i++)
41242  {
41243  vertex_coord[i+1] = right_node_pt->x(i);
41244  }
41245  local_vertex_nodes.insert(vertex_coord);
41246 
41247  // Mark as done only if one of its nodes has been
41248  // added to the list
41249  face_element_done[ele_face_pt] = true;
41250  nsorted_face_elements++;
41251 
41252  break;
41253  }
41254 
41255  } // if (!edge_done[edge])
41256  } // for (iiedge < nedges)
41257  }while(face_element_added &&
41258  (nsorted_face_elements < nnon_halo_face_element));
41259 
41260  // -----------------------------------------------------------------
41261  // At this point we already have a sorted set of nodes and
41262  // can be used to peform the unrefinement and refinement procedures
41263  // -----------------------------------------------------------------
41264 
41265  // Get the number of nodes on the list
41266  const unsigned nlocal_nodes = local_vertex_nodes.size();
41267  // Change representation to vector for easy of handling ...
41268  local_tmp_vector_vertex_node.resize(nlocal_nodes);
41269 
41270  // Copy the vertices of the nodes
41271  unsigned counter = 0;
41272  std::set<Vector<double> >::iterator it_vertex;
41273  for (it_vertex = local_vertex_nodes.begin();
41274  it_vertex != local_vertex_nodes.end();
41275  it_vertex++)
41276  {
41277  local_tmp_vector_vertex_node[counter].resize(3);
41278  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
41279  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
41280  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
41281  counter++;
41282  }
41283 
41284  // *********************************************************************
41285  // 3) Create the vertices along the boundary using the target area to
41286  // define the distance among them
41287  // *********************************************************************
41288 
41289  // Clear the local containter to recover the nodes ordered using the
41290  // zeta value
41291  local_vertex_nodes.clear();
41292 
41293  // At the end of each unrefinement/refinement step store the new nodes
41294  // on the set that will give rise to the vertices of the new polyline
41295  // representation
41296  unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
41297  for (unsigned i = 0; i < nnew_nodes; i++)
41298  {
41299  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
41300  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
41301  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
41302  vertex_nodes.insert(vertex_coord); // Global container
41303  local_vertex_nodes.insert(vertex_coord);
41304  }
41305 
41306 #ifdef OOMPH_HAS_MPI
41307  if (this->is_mesh_distributed())
41308  {
41309  // Add the set of vertices for the boundary, this will help to detect
41310  // if we need to deal with sub_boundaries and sub_polylines represen.
41311  sub_vertex_nodes.push_back(local_vertex_nodes);
41312  // Increase the counter for sub_boundaries
41313  nsub_boundaries++;
41314  }
41315 #endif
41316 
41317  } // while(nsorted_face_elements < nnon_halo_face_element)
41318 
41319  // Now turn into vector for ease of handling...
41320  unsigned npoly_vertex = vertex_nodes.size();
41321  tmp_vector_vertex_node.resize(npoly_vertex);
41322  unsigned count = 0;
41323  std::set<Vector<double> >::iterator it;
41324  for(it = vertex_nodes.begin(); it!=vertex_nodes.end(); ++it)
41325  {
41326  tmp_vector_vertex_node[count].resize(3);
41327  tmp_vector_vertex_node[count][0] = (*it)[0];
41328  tmp_vector_vertex_node[count][1] = (*it)[1];
41329  tmp_vector_vertex_node[count][2] = (*it)[2];
41330  ++count;
41331  }
41332 
41333 #ifdef OOMPH_HAS_MPI
41334  // --------- Stuff for the sub_boundaries ----- Begin section ---------
41335 #ifdef PARANOID
41336  unsigned nsub_boundaries_set = sub_vertex_nodes.size();
41337  if (nsub_boundaries_set != nsub_boundaries)
41338  {
41339  std::ostringstream error_message;
41340  error_message
41341  << "The number of found sub-boundaries and the number of counted\n"
41342  << "sub-boundaries are different:\n"
41343  << "Number of found sub-boundaries: ("<<nsub_boundaries_set<<")\n"
41344  << "Number of counted sub-boundaries: ("<<nsub_boundaries<<")\n";
41345  throw OomphLibError(error_message.str(),
41346  "RefineableTriangleMesh::update_polygon_after_restart()",
41347  OOMPH_EXCEPTION_LOCATION);
41348  }
41349 #endif
41350 
41351  // Verify if need to deal with sub_boundaries
41352  if (this->is_mesh_distributed() && nsub_boundaries > 1)
41353  {
41354  // Mark the boundary as been splitted in the partition process
41355  this->Boundary_was_splitted[bound] = true;
41356  // Resize the vector to store the info. of sub-boundaries
41357  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
41358  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
41359  {
41360  // Turn info. into vector for ease of handling...
41361  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
41362  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
41363  unsigned subcount = 0;
41364  std::set<Vector<double> >::iterator subit;
41365  for(subit = sub_vertex_nodes[isub].begin();
41366  subit != sub_vertex_nodes[isub].end(); ++subit)
41367  {
41368  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
41369  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
41370  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
41371  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
41372  ++subcount;
41373  }
41374  }
41375  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
41376  // --------- Stuff for the sub_boundaries ----- End section ------------
41377 #endif // OOMPH_HAS_MPI
41378 
41379 
41380  // For further processing the three-dimensional vector
41381  // has to be reduced to a two-dimensional vector
41382  unsigned n_vertex=tmp_vector_vertex_node.size();
41383 
41384  // Resize the vector for vectices
41385  vector_vertex_node.resize(n_vertex);
41386  for(unsigned i=0;i<n_vertex;i++)
41387  {
41388  vector_vertex_node[i].resize(2);
41389  vector_vertex_node[i][0]=tmp_vector_vertex_node[i][1];
41390  vector_vertex_node[i][1]=tmp_vector_vertex_node[i][2];
41391  }
41392 
41393 #ifdef OOMPH_HAS_MPI
41394  // --------- Stuff for the sub_boundaries ----- Begin section ----------
41395  // Verify if need to deal with sub_boundaries
41396  if (this->is_mesh_distributed() && nsub_boundaries > 1)
41397  {
41398  // For further processing the three-dimensional vector
41399  // has to be reduced to a two-dimensional vector
41400  // Resize the vector to store the info. of sub-boundaries
41401  sub_vector_vertex_node.resize(nsub_boundaries);
41402  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
41403  {
41404  const unsigned subn_vertex =
41405  sub_tmp_vector_vertex_node[isub].size();
41406  // Resize the vector for vectices
41407  sub_vector_vertex_node[isub].resize(subn_vertex);
41408  for(unsigned i=0;i<subn_vertex;i++)
41409  {
41410  sub_vector_vertex_node[isub][i].resize(2);
41411  sub_vector_vertex_node[isub][i][0]=
41412  sub_tmp_vector_vertex_node[isub][i][1];
41413  sub_vector_vertex_node[isub][i][1]=
41414  sub_tmp_vector_vertex_node[isub][i][2];
41415  }
41416  }
41417  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
41418 
41419  // We already have the info. for the sub-boundaries (if necessary)
41420  // and then we can create the sub-boundaries representations to
41421  // ease the generation of the mesh by Triangle
41422 
41423  // --------- Stuff for the sub_boundaries ----- End section ------------
41424 #endif // OOMPH_HAS_MPI
41425 
41426  // *********************************************************************
41427  // 4) Check for contiguousness
41428  // *********************************************************************
41429 #ifdef OOMPH_HAS_MPI
41430  // Only perform this checking if the mesh is not distributed
41431  // When the mesh is distributed the polylines continuity is
41432  // addressed with the sort_polylines_helper() method
41433  if (!this->is_mesh_distributed())
41434 #endif
41435  {
41436  if ( p > 0 )
41437  {
41438  //Final end point of previous line
41439  Vector<double> final_vertex_of_previous_segment;
41440  unsigned n_prev_vertex =
41441  polygon_pt->curve_section_pt(p-1)->nvertex();
41442  final_vertex_of_previous_segment =
41443  polygon_pt->polyline_pt(p-1)->
41444  vertex_coordinate(n_prev_vertex-1);
41445 
41446  unsigned prev_seg_boundary_id =
41447  polygon_pt->curve_section_pt(p-1)->boundary_id();
41448 
41449  //Find the error between the final vertex of the previous
41450  //line and the first vertex of the current line
41451  double error = 0.0;
41452  for(unsigned i=0;i<2;i++)
41453  {
41454  const double dist =
41455  final_vertex_of_previous_segment[i] -
41456  (*vector_vertex_node.begin())[i];
41457  error += dist*dist;
41458  }
41459  error = sqrt(error);
41460 
41461  //If the error is bigger than the tolerance then
41462  //we probably need to reverse, but better check
41463  if(error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
41464  {
41465  //Find the error between the final vertex of the previous
41466  //line and the last vertex of the current line
41467  double rev_error = 0.0;
41468  for(unsigned i=0;i<2;i++)
41469  {
41470  const double dist =
41471  final_vertex_of_previous_segment[i] -
41472  (*--vector_vertex_node.end())[i];
41473  rev_error += dist*dist;
41474  }
41475  rev_error = sqrt(rev_error);
41476 
41477  if(rev_error >
41478  ToleranceForVertexMismatchInPolygons::Tolerable_error)
41479  {
41480  // It could be possible that the first segment be reversed and we
41481  // did not notice it because this check does not apply for the
41482  // first segment. We can verify if the first segment is reversed
41483  // by using the vertex number 1
41484  if (p == 1)
41485  {
41486  //Initial end point of previous line
41487  Vector<double> initial_vertex_of_previous_segment;
41488 
41489  initial_vertex_of_previous_segment =
41490  polygon_pt->polyline_pt(p-1)->
41491  vertex_coordinate(0);
41492 
41493  unsigned prev_seg_boundary_id =
41494  polygon_pt->curve_section_pt(p-1)->boundary_id();
41495 
41496  //Find the error between the initial vertex of the previous
41497  //line and the first vertex of the current line
41498  double error = 0.0;
41499  for(unsigned i=0;i<2;i++)
41500  {
41501  const double dist =
41502  initial_vertex_of_previous_segment[i] -
41503  (*vector_vertex_node.begin())[i];
41504  error += dist*dist;
41505  }
41506  error = sqrt(error); // Reversed only the previous one
41507 
41508  //If the error is bigger than the tolerance then
41509  //we probably need to reverse, but better check
41510  if(error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
41511  {
41512  //Find the error between the final vertex of the previous
41513  //line and the last vertex of the current line
41514  double rev_error = 0.0;
41515  for(unsigned i=0;i<2;i++)
41516  {
41517  const double dist =
41518  initial_vertex_of_previous_segment[i] -
41519  (*--vector_vertex_node.end())[i];
41520  rev_error += dist*dist;
41521  }
41522  rev_error = sqrt(rev_error); // Reversed both the current one and
41523  // the previous one
41524 
41525  if (rev_error >
41526  ToleranceForVertexMismatchInPolygons::Tolerable_error)
41527  {
41528  std::ostringstream error_stream;
41529  error_stream
41530  <<"The distance between the first node of the current\n"
41531  <<"line segment (boundary " << bound << ") and either end of "
41532  << "the previous line segment\n"
41533  << "(boundary " << prev_seg_boundary_id << ") is bigger than "
41534  << "the desired tolerance " <<
41535  ToleranceForVertexMismatchInPolygons::Tolerable_error << ".\n"
41536  << "This suggests that the polylines defining the polygonal\n"
41537  << "representation are not properly ordered.\n"
41538  << "Fail on last vertex of polyline: ("
41539  << prev_seg_boundary_id<< ") and\nfirst vertex of polyline ("
41540  << bound << ").\nThis should have failed when first trying to"
41541  << " construct the\npolygon.\n";
41542  throw OomphLibError(error_stream.str(),
41543  "RefineableTriangleMesh::update_polygon_after_restart()",
41544  OOMPH_EXCEPTION_LOCATION);
41545  }
41546  else
41547  {
41548  // Reverse both
41549  // Reverse the current vector to line up with the previous one
41550  std::reverse(vector_vertex_node.begin(),
41551  vector_vertex_node.end());
41552  polygon_pt->polyline_pt(p-1)->reverse();
41553  }
41554  }
41555  else
41556  {
41557  // Reverse the previous one
41558  polygon_pt->polyline_pt(p-1)->reverse();
41559  }
41560 
41561  } // if p == 1
41562  else
41563  {
41564  std::ostringstream error_stream;
41565  error_stream
41566  <<"The distance between the first node of the current\n"
41567  <<"line segment (boundary " << bound << ") and either end of "
41568  <<"the previous line segment\n"
41569  <<"(boundary " << prev_seg_boundary_id << ") is bigger than the "
41570  <<"desired tolerance " <<
41571  ToleranceForVertexMismatchInPolygons::Tolerable_error << ".\n"
41572  <<"This suggests that the polylines defining the polygonal\n"
41573  <<"representation are not properly ordered.\n"
41574  << "Fail on last vertex of polyline: (" << prev_seg_boundary_id
41575  << ") and\nfirst vertex of polyline (" << bound << ").\n"
41576  << "This should have failed when first trying to construct the\n"
41577  << "polygon.\n";
41578  throw OomphLibError(
41579  error_stream.str(),
41580  "RefineableTriangleMesh::update_polygon_after_restart()",
41581  OOMPH_EXCEPTION_LOCATION);
41582  }
41583  }
41584  else
41585  {
41586  //Reverse the current vector to line up with the previous one
41587  std::reverse(vector_vertex_node.begin(),vector_vertex_node.end());
41588  }
41589  } // error
41590  } // p > 0
41591  } // is mesh not distributed
41592 
41593  // *********************************************************************
41594  // 5) Update the polylines representation
41595  // *********************************************************************
41596  // if (applied_area_length_constraint)
41597  // If only applied when there is a change then it keeps the
41598  // previous polyline representation, it means, it does not delete
41599  // the boundaries that are not part of the domain. We must update
41600  // the boundary representation
41601  {
41602  n_vertex = vector_vertex_node.size();
41603 
41604  // Now update the polyline according to the new vertices
41605  // The new one representation
41606  TriangleMeshPolyLine *tmp_polyline_pt =
41607  new TriangleMeshPolyLine(vector_vertex_node,bound);
41608 
41609  // for (unsigned h = 0; h < vector_vertex_node.size(); h++)
41610  // {
41611  // DEBP(h);
41612  // DEBP(vector_vertex_node[h][0]);
41613  // DEBP(vector_vertex_node[h][1]);
41614  // }
41615 
41616  // Create a temporal "curve section" version of the recently created
41617  // polyline
41618  TriangleMeshCurveSection *tmp_curve_section_pt = tmp_polyline_pt;
41619 
41620  // Tolerance below which the middle point can be deleted
41621  // (ratio of deflection to element length)
41622  double unrefinement_tolerance=
41623  polygon_pt->polyline_pt(p)->unrefinement_tolerance();
41624 
41625  // Tolerance to add points
41626  double refinement_tolerance=
41627  polygon_pt->polyline_pt(p)->refinement_tolerance();
41628 
41629  // Establish refinement and unrefinement tolerance
41630  tmp_polyline_pt->set_unrefinement_tolerance(
41631  unrefinement_tolerance);
41632  tmp_polyline_pt->set_refinement_tolerance(
41633  refinement_tolerance);
41634 
41635  // Establish the maximum length constraint
41636  double maximum_length = polygon_pt->polyline_pt(p)->maximum_length();
41637  tmp_polyline_pt->set_maximum_length(maximum_length);
41638 
41639  if (n_vertex >= 2)
41640  {
41641  // Pass the connection information from the old polyline to the
41642  // new one
41643  this->copy_connection_information(polygon_pt->polyline_pt(p),
41644  tmp_curve_section_pt);
41645  }
41646 
41647  //Now update the polyline according to the new vertices but
41648  //first check if the object is allowed to delete the representation
41649  //or if it should be done by other object
41650  bool delete_it_on_destructor = false;
41651 
41652  std::set<TriangleMeshCurveSection*>::iterator it =
41653  this->Free_curve_section_pt.find(polygon_pt->curve_section_pt(p));
41654 
41655  if (it!=this->Free_curve_section_pt.end())
41656  {
41657  this->Free_curve_section_pt.erase(it);
41658  delete polygon_pt->curve_section_pt(p);
41659  delete_it_on_destructor = true;
41660  }
41661 
41662  // *****************************************************************
41663  // Copying the new representation
41664  polygon_pt->curve_section_pt(p) = tmp_polyline_pt;
41665 
41666  // Update the Boundary - Polyline map
41667  this->Boundary_curve_section_pt[bound] = polygon_pt->curve_section_pt(p);
41668 
41669  if (delete_it_on_destructor)
41670  {
41671  this->Free_curve_section_pt.insert(polygon_pt->curve_section_pt(p));
41672  }
41673 
41674 #ifdef OOMPH_HAS_MPI
41675  // --------- Stuff for the sub_boundaries ----- Begin section --------
41676  // Verify if need to deal with sub_boundaries
41677  if (this->is_mesh_distributed() && nsub_boundaries > 1)
41678  {
41679  // Create temporary representations for the boundaries, only to
41680  // create the mesh when calling Triangle
41681  // Clear all previous stored data
41682  this->Boundary_subpolylines[bound].clear();
41683  // Now create storage for the sub-boundaries
41684  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
41685  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
41686  {
41687  // Now update the polyline according to the sub set of
41688  // vertices, set the chunk number of the polyline
41689  TriangleMeshPolyLine *sub_tmp_polyline_pt =
41690  new TriangleMeshPolyLine(sub_vector_vertex_node[isub], bound, isub);
41691 
41692  // Add the sub-polyline to the container to represent the boundary
41693  // in parts
41694  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
41695 
41696  // No need to send the unrefinement/refinement and maximum
41697  // length constraints since these are only temporary
41698  // representations. These polylines can be deleted once the
41699  // new polygons that represent the distributed domain have
41700  // been created
41701 
41702  } // for (isub < nsub_boundaries)
41703 
41704  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
41705  // --------- Stuff for the sub_boundaries ----- End section ---------
41706 #endif // OOMPH_HAS_MPI
41707 
41708  } // update polyline representation
41709 
41710  // Delete the allocated memory for the geometric object that
41711  // represents the curvilinear boundary
41712  delete mesh_geom_obj_pt;
41713 
41714  } // npolyline
41715 
41716  // Cleanup the face mesh
41717  for(unsigned p=0;p<n_polyline;p++)
41718  {
41719  face_mesh_pt[p]->flush_node_storage();
41720  delete face_mesh_pt[p];
41721  }
41722 
41723 }
41724 
41725 
41726 //======================================================================
41727 /// \short Updates the open curve representation after restart
41728 //======================================================================
41729 template <class ELEMENT>
41731 update_open_curve_after_restart(TriangleMeshOpenCurve* &open_curve_pt)
41732 {
41733  // **********************************************************************
41734  // 1) Get the vertices along the boundaries ids of the polylines and
41735  // update them
41736  // **********************************************************************
41737 
41738  // (1.1) Get the face mesh representation
41739  Vector<Mesh*> face_mesh_pt;
41740  get_face_mesh_representation(open_curve_pt,face_mesh_pt);
41741 
41742  // (1.2) Create vertices of the polylines by using the vertices of the
41743  // FaceElements
41744  Vector<double> vertex_coord(3); // zeta,x,y
41745  Vector<double> bound_left(1);
41746  Vector<double> bound_right(1);
41747 
41748  const unsigned ncurve_section = open_curve_pt->ncurve_section();
41749  // Go for each curve section
41750  for(unsigned cs = 0; cs < ncurve_section; cs++)
41751  {
41752  // Get the MeshAsGeomObject representation just once per polyline,
41753  // this object is only used by the
41754  // refine_boundary_constrained_by_target_area() method. We get it here
41755  // to ensure that all processors (in a distributed context) get this
41756  // representation just once, and because an AllToAll MPI communication
41757  // is used in this calling
41758  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt[cs]);
41759 
41760  //Get the boundary id
41761  const unsigned bound = open_curve_pt->curve_section_pt(cs)->boundary_id();
41762 
41763  /// Use a vector of vector for vertices and target areas to deal
41764  /// with the cases when the boundaries are split bn the
41765  /// distribution process. Internal boundaries may be completely or
41766  /// partially overlapped by shared boundaries
41767 
41768  // Loop over the face elements and add their vertices (they are
41769  // automatically sorted because of the set)
41770  const unsigned nface_element = face_mesh_pt[cs]->nelement();
41771  // Store the non halo elements and the element at the other side of
41772  // the boundary (whatever it be halo or not), the first will be the
41773  // ones from which we will get the vertices (in even position)
41774  Vector<FiniteElement*> non_halo_doubled_face_element_pt;
41775 
41776  // Map to store the index of the face element on a boundary
41777  std::map<FiniteElement*,unsigned> face_element_index_on_boundary;
41778 
41779  // Map to know the already sorted face elements
41780  std::map<FiniteElement*,bool> face_element_done;
41781 
41782  for(unsigned ef = 0; ef < nface_element; ++ef)
41783  {
41784  FiniteElement* ele_face_pt = face_mesh_pt[cs]->finite_element_pt(ef);
41785 
41786  // Skip the halo elements (not used as base elements, only
41787  // include those elements which one of its counterparts -- at the
41788  // other side of the boundary -- is non halo)
41789 #ifdef OOMPH_HAS_MPI
41790  if (this->is_mesh_distributed())
41791  {
41792  // Only work with non-halo elements
41793  if (ele_face_pt->is_halo()) {continue;}
41794  }
41795 #endif
41796 
41797  // Check if not already done
41798  if (!face_element_done[ele_face_pt])
41799  {
41800  // Add the element and look for the element at the other side
41801  // of the boundary to add it immediately after the new added
41802  // element
41803  non_halo_doubled_face_element_pt.push_back(ele_face_pt);
41804  // Create the map of the face element with the index
41805  face_element_index_on_boundary[ele_face_pt] = ef;
41806  // Mark the current element as done
41807  face_element_done[ele_face_pt] = true;
41808  // Get the number of nodes
41809  const unsigned nnodes = ele_face_pt->nnode();
41810  // Get the left and right node to look for the elements at the
41811  // other side of the boundary
41812  Node* left_node_pt = ele_face_pt->node_pt(0);
41813  Node* right_node_pt = ele_face_pt->node_pt(nnodes-1);
41814 
41815 #ifdef PARANOID
41816  // Flag to know if the element at the other side of the
41817  // boundary was found
41818  bool found_other_side_face_ele = false;
41819 #endif
41820  for (unsigned iface = 0; iface < nface_element; iface++)
41821  {
41822  // Get the candidate face element
41823  FiniteElement *cele_face_pt =
41824  face_mesh_pt[cs]->finite_element_pt(iface);
41825  // Check if not already done
41826  if (!face_element_done[cele_face_pt])
41827  {
41828  Node* cleft_node_pt = cele_face_pt->node_pt(0);
41829  Node* cright_node_pt = cele_face_pt->node_pt(nnodes-1);
41830 
41831  // Check if the nodes are the same
41832  if ((left_node_pt == cleft_node_pt &&
41833  right_node_pt == cright_node_pt) ||
41834  (left_node_pt == cright_node_pt &&
41835  right_node_pt == cleft_node_pt))
41836  {
41837  // Add the element to the storage
41838  non_halo_doubled_face_element_pt.push_back(cele_face_pt);
41839  // ... and mark the element as done
41840  face_element_done[cele_face_pt] = true;
41841  // Create the map of the face element with the index
41842  face_element_index_on_boundary[cele_face_pt] = iface;
41843 #ifdef PARANOID
41844  // Set the flag of found other side face element
41845  found_other_side_face_ele = true;
41846 #endif
41847  break;
41848  }
41849  }
41850  } // (iface < nface_element)
41851 
41852 #ifdef PARANOID
41853  if (!found_other_side_face_ele)
41854  {
41855  std::ostringstream error_message;
41856  error_message
41857  << "The face element at the other side of the boundary ("
41858  << bound << ") was not found!!\n"
41859  << "These are the nodes of the face element:\n"
41860  << "("<<left_node_pt->x(0)<<", "<<left_node_pt->x(1)<<") "
41861  << "and ("<<right_node_pt->x(0)<<","<<right_node_pt->x(1)<<")\n\n";
41862  throw OomphLibError(error_message.str(),
41863  "RefineableTriangleMesh::update_open_curve_after_restart()",
41864  OOMPH_EXCEPTION_LOCATION);
41865  }
41866 #endif
41867  } // if (!face_ele_done[ele_face_pt])
41868 
41869  } // (ef < nface_element)
41870 
41871  // Clear the map of the already done face elements
41872  // This will now be used to sort the face elements
41873  face_element_done.clear();
41874 
41875  // Set of coordinates that are on the boundary
41876  // The entries are sorted on first entry in vector which stores
41877  // the boundary coordinate so the vertices come out in order!
41878  std::set<Vector<double> > vertex_nodes;
41879 
41880  // Vector to store the vertices, transfer the sorted vertices from the
41881  // set to this vector, --- including the z-value ---
41882  Vector<Vector<double> > tmp_vector_vertex_node;
41883 
41884  // Vector to store the coordinates of the polylines, same as the
41885  // tmp_vector_vertex_node vector (after adding more nodes) but
41886  // --- without the z-value ---, used to re-generate the polylines
41887  Vector<Vector<double> > vector_vertex_node;
41888 
41889 #ifdef OOMPH_HAS_MPI
41890  // Indicates if the set of vertices give rise to a internal
41891  // boundary that will be used as shared boundary or as normal
41892  // internal boundary -- Only used to deal with internal boundaries
41893  // in a distributed scheme
41894  std::vector<bool> internal_to_shared_boundary;
41895 
41896  // --------- Stuff to deal with splitted boundaries ---------- Begin -----
41897  // Set of coordinates that are on the boundary (splitted boundary version)
41898  // The first vector is used to allocate the points for each sub-boundary
41899  // Set entries are ordered on first entry in vector which stores
41900  // the boundary coordinate so the vertices come out in order!
41901  Vector<std::set<Vector<double> > > sub_vertex_nodes;
41902 
41903  // Vector to store the vertices, transfer the sorted vertices from the
41904  // set (sub_vertex_nodes) to this vector, --- including the z-value ---
41905  Vector<Vector<Vector<double> > > sub_tmp_vector_vertex_node;
41906 
41907  // Vector to store the coordinates of the polylines that will represent
41908  // the splitted boundary. Used to pass the info. from sub_vertex_nodes
41909  // but --- without the z-value ---, used to generate the sub-polylines
41910  Vector<Vector<Vector<double> > > sub_vector_vertex_node;
41911 
41912  // --------- Stuff to deal with splitted boundaries ----------- End ------
41913 #endif
41914 
41915  // Sort face elements, separate those with both nonhalo face
41916  // elements from those with one halo and one nonhalo face element
41917 
41918  // Number of done face elements
41919  unsigned nsorted_face_elements = 0;
41920 
41921 #ifdef OOMPH_HAS_MPI
41922  // Counter for sub_boundaries
41923  unsigned nsub_boundaries = 0;
41924 #endif // #ifdef OOMPH_HAS_MPI
41925 
41926  // Total number of non halo double face element
41927  const unsigned nnon_halo_doubled_face_ele =
41928  non_halo_doubled_face_element_pt.size();
41929 
41930  // Continue until all the face elements have been sorted
41931  // This while is to deal with the cases of splitted boundaries
41932  while(nsorted_face_elements < nnon_halo_doubled_face_ele)
41933  {
41934  // Get and initial face element
41935  FiniteElement* ele_face_pt = 0;
41936  FiniteElement* repeated_ele_face_pt = 0;
41937 #ifdef PARANOID
41938  bool found_initial_face_element = false;
41939 #endif
41940 
41941  // Flag to know if we are working with a face element which the
41942  // face element at the other side of the boundary is also non
41943  // halo
41944  bool both_root_face_elements_are_nonhalo = false;
41945 
41946  unsigned iface = 0;
41947  for (iface = 0; iface < nnon_halo_doubled_face_ele; iface+=2)
41948  {
41949  ele_face_pt = non_halo_doubled_face_element_pt[iface];
41950  // If not done then take it as initial face element
41951  if (!face_element_done[ele_face_pt])
41952  {
41953  // Mark it as done
41954  face_element_done[ele_face_pt] = true;
41955  // Get the other side boundary face element
41956  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iface+1];
41957  // ... also mark as done the repeated face element
41958  face_element_done[repeated_ele_face_pt] = true;
41959 
41960 #ifdef OOMPH_HAS_MPI
41961  if (!repeated_ele_face_pt->is_halo())
41962  {both_root_face_elements_are_nonhalo = true;}
41963 #endif // #ifdef OOMPH_HAS_MPI
41964 
41965  // Plus two because internal boundaries have
41966  // two face elements per each edge
41967  nsorted_face_elements+=2;
41968  iface+=2;
41969 #ifdef PARANOID
41970  // And set the flag to true
41971  found_initial_face_element = true;
41972 #endif
41973  break;
41974  }
41975  }
41976 
41977 #ifdef PARANOID
41978  if (!found_initial_face_element)
41979  {
41980  std::ostringstream error_message;
41981  error_message
41982  <<"Could not find an initial face element for the current segment\n";
41983  // << "----- Possible memory leak -----\n";
41984  throw OomphLibError(error_message.str(),
41985  OOMPH_CURRENT_FUNCTION,
41986  OOMPH_EXCEPTION_LOCATION);
41987  }
41988 #endif
41989 
41990  // Local set of coordinates that are on the boundary Set entries
41991  // are ordered on first entry in vector which stores the boundary
41992  // coordinate so the vertices come out in order
41993  std::set<Vector<double> > local_vertex_nodes;
41994 
41995  // Vector to store the vertices, transfer the sorted vertices from the
41996  // set (local) to this vector (local), --- including the z-value ---
41997  Vector<Vector<double> > local_tmp_vector_vertex_node;
41998 
41999  // ------------------------------------------------------------------
42000  // ------------------------------------------------------------------
42001  // Add the vertices of the initial face element to the set of local
42002  // sorted vertices
42003  // ------------------------------------------------------------------
42004  // ------------------------------------------------------------------
42005  const unsigned nnode = ele_face_pt->nnode();
42006  // Add the left-hand node to the set:
42007  // Boundary coordinate
42008  ele_face_pt->node_pt(0)->get_coordinates_on_boundary(bound,bound_left);
42009  vertex_coord[0] = bound_left[0];
42010 
42011  // Actual coordinates
42012  for(unsigned i=0;i<2;i++)
42013  {
42014  vertex_coord[i+1] = ele_face_pt->node_pt(0)->x(i);
42015  }
42016  local_vertex_nodes.insert(vertex_coord);
42017 
42018  // Add the right-hand node to the set:
42019  // Boundary coordinate
42020  ele_face_pt->node_pt(nnode-1)->get_coordinates_on_boundary(bound,
42021  bound_right);
42022  vertex_coord[0] = bound_right[0];
42023 
42024  // Actual coordinates
42025  for(unsigned i=0;i<2;i++)
42026  {
42027  vertex_coord[i+1] = ele_face_pt->node_pt(nnode-1)->x(i);
42028  }
42029  local_vertex_nodes.insert(vertex_coord);
42030 
42031  // The initial and final node on the set
42032  Node *first_node_pt = ele_face_pt->node_pt(0);
42033  Node *last_node_pt = ele_face_pt->node_pt(nnode-1);
42034 
42035  // Continue iterating if a new face element has been added to the
42036  // list
42037  bool face_element_added = false;
42038 
42039  // While a new face element has been added to the set of sorted
42040  // face elements then re-iterate
42041  do
42042  {
42043  // Start from the next face elements since we have already
42044  // added the previous one as the initial face element (any
42045  // previous face element had to be added on previous
42046  // iterations)
42047  for (unsigned iiface=iface;
42048  iiface<nnon_halo_doubled_face_ele;iiface+=2)
42049  {
42050  face_element_added = false;
42051  ele_face_pt = non_halo_doubled_face_element_pt[iiface];
42052 
42053  // Check that the face element with which we are working has
42054  // the same conditions as the root face element (both faces
42055  // are nonhalo or one face is halo and the other nonhalo)
42056 
42057  // Get the face element at the other side of the boundary
42058  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iiface+1];
42059  bool both_face_elements_are_nonhalo = false;
42060 
42061 #ifdef OOMPH_HAS_MPI
42062  if (!repeated_ele_face_pt->is_halo())
42063  {both_face_elements_are_nonhalo = true;}
42064 #endif // #ifdef OOMPH_HAS_MPI
42065 
42066  if (!face_element_done[ele_face_pt] &&
42067  (both_face_elements_are_nonhalo ==
42068  both_root_face_elements_are_nonhalo))
42069  {
42070  // Get each individual node to check if they are contiguous
42071  const unsigned nlnode = ele_face_pt->nnode();
42072  Node* left_node_pt = ele_face_pt->node_pt(0);
42073  Node* right_node_pt = ele_face_pt->node_pt(nlnode-1);
42074 
42075  if (left_node_pt == first_node_pt)
42076  {
42077  first_node_pt = right_node_pt;
42078  face_element_added = true;
42079  }
42080  else if (left_node_pt == last_node_pt)
42081  {
42082  last_node_pt = right_node_pt;
42083  face_element_added = true;
42084  }
42085  else if (right_node_pt == first_node_pt)
42086  {
42087  first_node_pt = left_node_pt;
42088  face_element_added = true;
42089  }
42090  else if (right_node_pt == last_node_pt)
42091  {
42092  last_node_pt = left_node_pt;
42093  face_element_added = true;
42094  }
42095 
42096  if (face_element_added)
42097  {
42098  // Add the left-hand node to the set:
42099  // Boundary coordinate
42100  left_node_pt->get_coordinates_on_boundary(bound,bound_left);
42101  vertex_coord[0] = bound_left[0];
42102 
42103  // Actual coordinates
42104  for(unsigned i=0;i<2;i++)
42105  {
42106  vertex_coord[i+1] = left_node_pt->x(i);
42107  }
42108  local_vertex_nodes.insert(vertex_coord);
42109 
42110  // Add the right-hand nodes to the set:
42111  // Boundary coordinate
42112  right_node_pt->get_coordinates_on_boundary(bound,bound_right);
42113  vertex_coord[0] = bound_right[0];
42114 
42115  // Actual coordinates
42116  for(unsigned i=0;i<2;i++)
42117  {
42118  vertex_coord[i+1] = right_node_pt->x(i);
42119  }
42120  local_vertex_nodes.insert(vertex_coord);
42121 
42122  // Mark as done only if one of its nodes has been
42123  // added to the list
42124  face_element_done[ele_face_pt] = true;
42125  // .. also mark as done the face element at the othe side of
42126  // the boundary
42127  repeated_ele_face_pt = non_halo_doubled_face_element_pt[iiface+1];
42128  face_element_done[repeated_ele_face_pt] = true;
42129  // ... and increase the number of sorted face elements
42130  nsorted_face_elements+=2;
42131 
42132  break;
42133  }
42134 
42135  } // if (!face_element_done[[ele_face_pt])
42136  } // for (iiface<nnon_halo_doubled_face_ele)
42137  }while(face_element_added &&
42138  (nsorted_face_elements < nnon_halo_doubled_face_ele));
42139 
42140  // -------------------------------------------------------------
42141  // At this point we already have a sorted set of nodes and can
42142  // be used to peform the unrefinement and refinement procedures
42143  // -------------------------------------------------------------
42144 
42145  // Get the number of nodes on the list
42146  const unsigned nlocal_nodes = local_vertex_nodes.size();
42147  // Change representation to vector for easy of handling ...
42148  local_tmp_vector_vertex_node.resize(nlocal_nodes);
42149 
42150  // Copy the vertices of the nodes
42151  unsigned counter = 0;
42152  std::set<Vector<double> >::iterator it_vertex;
42153  for (it_vertex = local_vertex_nodes.begin();
42154  it_vertex != local_vertex_nodes.end();
42155  it_vertex++)
42156  {
42157  local_tmp_vector_vertex_node[counter].resize(3);
42158  local_tmp_vector_vertex_node[counter][0] = (*it_vertex)[0];
42159  local_tmp_vector_vertex_node[counter][1] = (*it_vertex)[1];
42160  local_tmp_vector_vertex_node[counter][2] = (*it_vertex)[2];
42161  counter++;
42162  }
42163 
42164  // The unrefinement and refinement process needs to be applied
42165  // from the bottom-left node since the internal open curve could
42166  // lie on the shared boundaries
42167  if (local_tmp_vector_vertex_node[nlocal_nodes-1][2] <
42168  local_tmp_vector_vertex_node[0][2])
42169  {
42170  std::reverse(local_tmp_vector_vertex_node.begin(),
42171  local_tmp_vector_vertex_node.end());
42172  }
42173  else if (local_tmp_vector_vertex_node[nlocal_nodes-1][2] ==
42174  local_tmp_vector_vertex_node[0][2])
42175  {
42176  if (local_tmp_vector_vertex_node[nlocal_nodes-1][1] <
42177  local_tmp_vector_vertex_node[0][1])
42178  {
42179  std::reverse(local_tmp_vector_vertex_node.begin(),
42180  local_tmp_vector_vertex_node.end());
42181  }
42182  }
42183 
42184  // ****************************************************************
42185  // 3) Create the vertices along the boundary using the target
42186  // area to define the distance among them
42187  // ****************************************************************
42188 
42189  // Clear the local containter to recover the nodes ordered using
42190  // the zeta value
42191  local_vertex_nodes.clear();
42192 
42193  // At the end of each unrefinement/refinement step store the new
42194  // nodes on the set that will give rise to the vertices of the
42195  // new polyline representation
42196  const unsigned nnew_nodes = local_tmp_vector_vertex_node.size();
42197  for (unsigned i = 0; i < nnew_nodes; i++)
42198  {
42199  vertex_coord[0] = local_tmp_vector_vertex_node[i][0];
42200  vertex_coord[1] = local_tmp_vector_vertex_node[i][1];
42201  vertex_coord[2] = local_tmp_vector_vertex_node[i][2];
42202  vertex_nodes.insert(vertex_coord); // Global container
42203  local_vertex_nodes.insert(vertex_coord);
42204  }
42205 
42206 #ifdef OOMPH_HAS_MPI
42207  if (this->is_mesh_distributed())
42208  {
42209  // Add the set of vertices for the boundary, this will help to
42210  // detect if we need to deal with sub_boundaries and
42211  // sub_polylines representations
42212  sub_vertex_nodes.push_back(local_vertex_nodes);
42213  // Increase the counter for sub_boundaries
42214  nsub_boundaries++;
42215 
42216  // Mark if the polyline created by these vertices will be used
42217  // as a shared boundary or as an internal boundary
42218  if (both_root_face_elements_are_nonhalo)
42219  {internal_to_shared_boundary.push_back(false);}
42220  else
42221  {internal_to_shared_boundary.push_back(true);}
42222  }
42223 #endif
42224 
42225  } // while(nsorted_face_elements < nnon_halo_doubled_face_ele)
42226  // This while is in charge of sorting all the face elements to
42227  // create the new representation of the polyline (also deals
42228  // with the sub-boundary cases)
42229 
42230  // Now turn into vector for ease of handling...
42231  const unsigned npoly_vertex = vertex_nodes.size();
42232  tmp_vector_vertex_node.resize(npoly_vertex);
42233  unsigned count = 0;
42234  std::set<Vector<double> >::iterator it;
42235  for (it = vertex_nodes.begin(); it!=vertex_nodes.end(); ++it)
42236  {
42237  tmp_vector_vertex_node[count].resize(3);
42238  tmp_vector_vertex_node[count][0] = (*it)[0];
42239  tmp_vector_vertex_node[count][1] = (*it)[1];
42240  tmp_vector_vertex_node[count][2] = (*it)[2];
42241  ++count;
42242  }
42243 
42244 #ifdef OOMPH_HAS_MPI
42245  // Check that the number of set of vertices marked to be shared or
42246  // internal boundaries be the same as the total number of
42247  // sub-boundaries
42248 #ifdef PARANOID
42249  const unsigned nsub_boundaries_set = sub_vertex_nodes.size();
42250  const unsigned ninternal_to_shared_boundaries =
42251  internal_to_shared_boundary.size();
42252  if (nsub_boundaries_set != ninternal_to_shared_boundaries)
42253  {
42254  std::ostringstream error_message;
42255  error_message
42256  << "The number of found sub-boundaries and the number of marked "
42257  << "internal\nboundaries are different\n"
42258  << "Number of found sub-boundaries: ("<<nsub_boundaries_set<<")\n"
42259  << "Number of marked internal boundaries: ("
42260  << ninternal_to_shared_boundaries << ")\n\n";
42261  throw OomphLibError(error_message.str(),
42262  "RefineableTriangleMesh::update_open_curve_after_restart()",
42263  OOMPH_EXCEPTION_LOCATION);
42264  }
42265 #endif
42266 
42267  // --------- Stuff for the sub_boundaries ----- Begin section -------
42268 #ifdef PARANOID
42269  if (nsub_boundaries_set != nsub_boundaries)
42270  {
42271  std::ostringstream error_message;
42272  error_message
42273  << "The number of found sub-boundaries and the number of counted\n"
42274  << "sub-boundaries are different:\n"
42275  << "Number of found sub-boundaries: ("<<nsub_boundaries_set<<")\n"
42276  << "Number of counted sub-boundaries: ("<<nsub_boundaries<<")\n\n";
42277  throw OomphLibError(error_message.str(),
42278  "RefineableTriangleMesh::update_open_curve_after_restart()",
42279  OOMPH_EXCEPTION_LOCATION);
42280  }
42281 #endif
42282 
42283  // Verify if need to deal with sub_boundaries
42284  if (this->is_mesh_distributed() && nsub_boundaries > 1)
42285  {
42286  // Mark the boundary as been splitted in the partition process
42287  this->Boundary_was_splitted[bound] = true;
42288  // Resize the vector to store the info. of sub-boundaries
42289  sub_tmp_vector_vertex_node.resize(nsub_boundaries);
42290  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
42291  {
42292  // Turn info. into vector for ease of handling...
42293  const unsigned nsubpoly_vertex = sub_vertex_nodes[isub].size();
42294  sub_tmp_vector_vertex_node[isub].resize(nsubpoly_vertex);
42295  unsigned subcount = 0;
42296  std::set<Vector<double> >::iterator subit;
42297  for(subit = sub_vertex_nodes[isub].begin();
42298  subit != sub_vertex_nodes[isub].end(); ++subit)
42299  {
42300  sub_tmp_vector_vertex_node[isub][subcount].resize(3);
42301  sub_tmp_vector_vertex_node[isub][subcount][0] = (*subit)[0];
42302  sub_tmp_vector_vertex_node[isub][subcount][1] = (*subit)[1];
42303  sub_tmp_vector_vertex_node[isub][subcount][2] = (*subit)[2];
42304  ++subcount;
42305  }
42306  }
42307  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
42308  // --------- Stuff for the sub_boundaries ----- End section ----------
42309 #endif // OOMPH_HAS_MPI
42310 
42311  // For further processing the three-dimensional vector has to be
42312  // reduced to a two-dimensional vector
42313  unsigned n_vertex=tmp_vector_vertex_node.size();
42314 
42315  // Resize the vector for vectices
42316  vector_vertex_node.resize(n_vertex);
42317  for(unsigned i=0;i<n_vertex;i++)
42318  {
42319  vector_vertex_node[i].resize(2);
42320  vector_vertex_node[i][0]=tmp_vector_vertex_node[i][1];
42321  vector_vertex_node[i][1]=tmp_vector_vertex_node[i][2];
42322  }
42323 
42324 #ifdef OOMPH_HAS_MPI
42325  // --------- Stuff for the sub_boundaries ----- Begin section ----------
42326  // Verify if need to deal with sub_boundaries
42327  if (this->is_mesh_distributed() && nsub_boundaries > 1)
42328  {
42329  // For further processing the three-dimensional vector
42330  // has to be reduced to a two-dimensional vector
42331  // Resize the vector to store the info. of sub-boundaries
42332  sub_vector_vertex_node.resize(nsub_boundaries);
42333  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
42334  {
42335  const unsigned subn_vertex =
42336  sub_tmp_vector_vertex_node[isub].size();
42337  // Resize the vector for vectices
42338  sub_vector_vertex_node[isub].resize(subn_vertex);
42339  for(unsigned i=0;i<subn_vertex;i++)
42340  {
42341  sub_vector_vertex_node[isub][i].resize(2);
42342  sub_vector_vertex_node[isub][i][0]=
42343  sub_tmp_vector_vertex_node[isub][i][1];
42344  sub_vector_vertex_node[isub][i][1]=
42345  sub_tmp_vector_vertex_node[isub][i][2];
42346  }
42347  }
42348  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
42349 
42350  // We already have the info. for the sub-boundaries (if necessary) and
42351  // then we can create the sub-boundaries representations to ease the
42352  // generation of the mesh by Triangle
42353 
42354  // --------- Stuff for the sub_boundaries ----- End section ------------
42355 #endif // OOMPH_HAS_MPI
42356 
42357  // *********************************************************************
42358  // 4) Check for contiguousness
42359  // *********************************************************************
42360 #ifdef OOMPH_HAS_MPI
42361  // Only perform this checking if the mesh is not distributed
42362  // When the mesh is distributed the polylines continuity is
42363  // addressed with the sort_polylines_helper() method
42364  if (!this->is_mesh_distributed())
42365 #endif
42366  {
42367  if ( cs > 0 )
42368  {
42369  //Final end point of previous line
42370  Vector<double> final_vertex_of_previous_segment;
42371  unsigned n_prev_vertex =
42372  open_curve_pt->curve_section_pt(cs-1)->nvertex();
42373  final_vertex_of_previous_segment =
42374  open_curve_pt->polyline_pt(cs-1)->
42375  vertex_coordinate(n_prev_vertex-1);
42376 
42377  unsigned prev_seg_boundary_id =
42378  open_curve_pt->curve_section_pt(cs-1)->boundary_id();
42379 
42380  //Find the error between the final vertex of the previous
42381  //line and the first vertex of the current line
42382  double error = 0.0;
42383  for(unsigned i=0;i<2;i++)
42384  {
42385  const double dist =
42386  final_vertex_of_previous_segment[i] -
42387  (*vector_vertex_node.begin())[i];
42388  error += dist*dist;
42389  }
42390  error = sqrt(error);
42391 
42392  //If the error is bigger than the tolerance then
42393  //we probably need to reverse, but better check
42394  if(error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
42395  {
42396  //Find the error between the final vertex of the previous
42397  //line and the last vertex of the current line
42398  double rev_error = 0.0;
42399  for(unsigned i=0;i<2;i++)
42400  {
42401  const double dist =
42402  final_vertex_of_previous_segment[i] -
42403  (*--vector_vertex_node.end())[i];
42404  rev_error += dist*dist;
42405  }
42406  rev_error = sqrt(rev_error);
42407 
42408  if(rev_error >
42409  ToleranceForVertexMismatchInPolygons::Tolerable_error)
42410  {
42411  // It could be possible that the first segment be reversed and we
42412  // did not notice it because this check does not apply for the
42413  // first segment. We can verify if the first segment is reversed
42414  // by using the vertex number 1
42415  if (cs == 1)
42416  {
42417  //Initial end point of previous line
42418  Vector<double> initial_vertex_of_previous_segment;
42419 
42420  initial_vertex_of_previous_segment =
42421  open_curve_pt->polyline_pt(cs-1)->vertex_coordinate(0);
42422 
42423  unsigned prev_seg_boundary_id =
42424  open_curve_pt->curve_section_pt(cs-1)->boundary_id();
42425 
42426  //Find the error between the initial vertex of the previous
42427  //line and the first vertex of the current line
42428  double error = 0.0;
42429  for(unsigned i=0;i<2;i++)
42430  {
42431  const double dist =
42432  initial_vertex_of_previous_segment[i] -
42433  (*vector_vertex_node.begin())[i];
42434  error += dist*dist;
42435  }
42436  error = sqrt(error); // Reversed only the previous one
42437 
42438  //If the error is bigger than the tolerance then
42439  //we probably need to reverse, but better check
42440  if(error > ToleranceForVertexMismatchInPolygons::Tolerable_error)
42441  {
42442  //Find the error between the final vertex of the previous
42443  //line and the last vertex of the current line
42444  double rev_error = 0.0;
42445  for(unsigned i=0;i<2;i++)
42446  {
42447  const double dist =
42448  initial_vertex_of_previous_segment[i] -
42449  (*--vector_vertex_node.end())[i];
42450  rev_error += dist*dist;
42451  }
42452  rev_error = sqrt(rev_error); // Reversed both the current
42453  // one and the previous one
42454 
42455  if (rev_error >
42456  ToleranceForVertexMismatchInPolygons::Tolerable_error)
42457  {
42458  std::ostringstream error_stream;
42459  error_stream
42460  <<"The distance between the first node of the current\n"
42461  <<"line segment (boundary "<<bound<<") and either end of "
42462  <<"the previous line segment\n"
42463  <<"(boundary "<<prev_seg_boundary_id<<") is bigger than"
42464  << " the desired tolerance " <<
42465  ToleranceForVertexMismatchInPolygons::Tolerable_error<<".\n"
42466  <<"This suggests that the polylines defining the polygonal\n"
42467  <<"representation are not properly ordered.\n"
42468  <<"Fail on last vertex of polyline: ("
42469  <<prev_seg_boundary_id<<") and\nfirst vertex of polyline ("
42470  <<bound<< ").\nThis should have failed when first trying to "
42471  <<"construct the\npolygon.\n";
42472  throw OomphLibError(error_stream.str(),
42473  "RefineableTriangleMesh::update_open_curve_after_restart()",
42474  OOMPH_EXCEPTION_LOCATION);
42475  }
42476  else
42477  {
42478  // Reverse both
42479  // Reverse the current vector to line up with the previous one
42480  std::reverse(vector_vertex_node.begin(),
42481  vector_vertex_node.end());
42482  open_curve_pt->polyline_pt(cs-1)->reverse();
42483  }
42484  }
42485  else
42486  {
42487  // Reverse the previous one
42488  open_curve_pt->polyline_pt(cs-1)->reverse();
42489  }
42490 
42491  } // if (cs == 1)
42492  else
42493  {
42494  std::ostringstream error_stream;
42495  error_stream
42496  <<"The distance between the first node of the current\n"
42497  <<"line segment (boundary " << bound << ") and either end of "
42498  <<"the previous line segment\n"
42499  <<"(boundary " << prev_seg_boundary_id << ") is bigger than the "
42500  <<"desired tolerance " <<
42501  ToleranceForVertexMismatchInPolygons::Tolerable_error << ".\n"
42502  <<"This suggests that the polylines defining the polygonal\n"
42503  <<"representation are not properly ordered.\n"
42504  <<"Fail on last vertex of polyline: (" << prev_seg_boundary_id
42505  <<") and\nfirst vertex of polyline (" << bound << ").\n"
42506  <<"This should have failed when first trying to construct the\n"
42507  <<"polygon.\n";
42508  throw OomphLibError(
42509  error_stream.str(),
42510  "RefineableTriangleMesh::update_open_curve_after_restart()",
42511  OOMPH_EXCEPTION_LOCATION);
42512  }
42513  }
42514  else
42515  {
42516  //Reverse the current vector to line up with the previous one
42517  std::reverse(vector_vertex_node.begin(),vector_vertex_node.end());
42518  }
42519  } // error
42520  } // (cs > 0)
42521  } // is mesh not distributed
42522 
42523  // DEBP(applied_area_length_constraint);
42524  // DEBP(p);
42525  // getchar();
42526  // *********************************************************************
42527  // 5) Update the polylines representation
42528  // *********************************************************************
42529  // if (applied_area_length_constraint)
42530  // If only applied when there is a change then it keeps the
42531  // previous polyline representation, it means, it does not delete
42532  // the boundaries that are not part of the domain. We must update
42533  // the boundary representation
42534  {
42535  n_vertex = vector_vertex_node.size();
42536 
42537  // Now update the polyline according to the new vertices
42538  // The new one representation
42539  TriangleMeshPolyLine *tmp_polyline_pt =
42540  new TriangleMeshPolyLine(vector_vertex_node,bound);
42541 
42542  // Create a temporal "curve section" version of the recently created
42543  // polyline
42544  TriangleMeshCurveSection *tmp_curve_section_pt = tmp_polyline_pt;
42545 
42546  // Tolerance below which the middle point can be deleted
42547  // (ratio of deflection to element length)
42548  double unrefinement_tolerance=
42549  open_curve_pt->polyline_pt(cs)->unrefinement_tolerance();
42550 
42551  // Tolerance to add points
42552  double refinement_tolerance=
42553  open_curve_pt->polyline_pt(cs)->refinement_tolerance();
42554 
42555  // Establish refinement and unrefinement tolerance
42556  tmp_polyline_pt->set_unrefinement_tolerance(unrefinement_tolerance);
42557  tmp_polyline_pt->set_refinement_tolerance(refinement_tolerance);
42558 
42559  // Establish the maximum length constraint
42560  double maximum_length = open_curve_pt->polyline_pt(cs)->maximum_length();
42561  tmp_polyline_pt->set_maximum_length(maximum_length);
42562 
42563  if (n_vertex >= 2)
42564  {
42565  // Pass the connection information from the old polyline to the
42566  // new one
42567  this->copy_connection_information(open_curve_pt->polyline_pt(cs),
42568  tmp_curve_section_pt);
42569  }
42570 
42571  //Now update the polyline according to the new vertices but first
42572  //check if the object is allowed to delete the representation or
42573  //if it should be done by other object
42574  bool delete_it_on_destructor = false;
42575 
42576  std::set<TriangleMeshCurveSection*>::iterator it =
42577  this->Free_curve_section_pt.find(open_curve_pt->curve_section_pt(cs));
42578 
42579  if (it!=this->Free_curve_section_pt.end())
42580  {
42581  this->Free_curve_section_pt.erase(it);
42582  delete open_curve_pt->curve_section_pt(cs);
42583  delete_it_on_destructor = true;
42584  }
42585 
42586  // *****************************************************************
42587  // Copying the new representation
42588  open_curve_pt->curve_section_pt(cs) = tmp_polyline_pt;
42589 
42590  // Update the Boundary - Polyline map
42591  this->Boundary_curve_section_pt[bound]=open_curve_pt->curve_section_pt(cs);
42592 
42593  if (delete_it_on_destructor)
42594  {
42595  this->Free_curve_section_pt.insert(open_curve_pt->curve_section_pt(cs));
42596  }
42597 
42598 #ifdef OOMPH_HAS_MPI
42599 
42600  // If there are not sub-boundaries mark the boundary if need to be
42601  // trated as shared or as internal boundary
42602  if (this->is_mesh_distributed() && nsub_boundaries == 1)
42603  {
42604  // Clear all previous stored data
42605  this->Boundary_marked_as_shared_boundary[bound].clear();
42606 
42607  // .. and store the flag for the boundary
42608  this->Boundary_marked_as_shared_boundary[bound].push_back(
42609  internal_to_shared_boundary[0]);
42610  }
42611  // --------- Stuff for the sub_boundaries ----- Begin section --------
42612  // Verify if need to deal with sub_boundaries
42613  else if (this->is_mesh_distributed() && nsub_boundaries > 1)
42614  {
42615  // Create temporary representations for the boundaries, only to
42616  // create the mesh when calling Triangle
42617  // Clear all previous stored data
42618  this->Boundary_subpolylines[bound].clear();
42619  // Now create storage for the sub-boundaries
42620  this->Boundary_subpolylines[bound].resize(nsub_boundaries);
42621 
42622  // Clear all previous stored data
42623  this->Boundary_marked_as_shared_boundary[bound].clear();
42624  // Create storage to mark the internal boundaries as shared
42625  // boundaries
42626  this->Boundary_marked_as_shared_boundary[bound].resize(nsub_boundaries);
42627  for (unsigned isub = 0; isub < nsub_boundaries; isub++)
42628  {
42629  // Now update the polyline according to the sub set of
42630  // vertices, set the chunk number of the polyline
42631  TriangleMeshPolyLine *sub_tmp_polyline_pt =
42632  new TriangleMeshPolyLine(sub_vector_vertex_node[isub], bound, isub);
42633 
42634  // Add the sub-polyline to the container to represent the
42635  // boundary in parts
42636  this->Boundary_subpolylines[bound][isub] = sub_tmp_polyline_pt;
42637 
42638  // Copy the flag that mark the boundary as internal or as
42639  // shared bound
42640  this->Boundary_marked_as_shared_boundary[bound][isub] =
42641  internal_to_shared_boundary[isub];
42642 
42643  // No need to send the unrefinement/refinement and maximum
42644  // length constraints since these are only temporary
42645  // representations
42646 
42647  }
42648 
42649  } // if (this->is_mesh_distributed() && nsub_boundaries > 1)
42650  // --------- Stuff for the sub_boundaries ----- End section ---------
42651 #endif // OOMPH_HAS_MPI
42652 
42653  } // update polyline representation
42654 
42655  // Delete the allocated memory for the geometric object
42656  // that represents the curvilinear boundary
42657  delete mesh_geom_obj_pt;
42658 
42659  } // npolyline
42660 
42661  // Cleanup the face mesh
42662  for(unsigned p = 0; p < ncurve_section; p++)
42663  {
42664  face_mesh_pt[p]->flush_node_storage();
42665  delete face_mesh_pt[p];
42666  }
42667 
42668 }
42669 
42670 #ifdef OOMPH_HAS_MPI
42671 //======================================================================
42672 /// \short Updates the shared polylines representation after restart
42673 //======================================================================
42674 template <class ELEMENT>
42676 update_shared_curve_after_restart(Vector<TriangleMeshPolyLine*>
42677  &vector_polyline_pt)
42678 {
42679  // Go through all the shared boundaries/polylines
42680  const unsigned npolylines = vector_polyline_pt.size();
42681  for (unsigned pp = 0; pp < npolylines; pp++)
42682  {
42683  // Get the boundary of the current polyline
42684  const unsigned b = vector_polyline_pt[pp]->boundary_id();
42685 
42686  // Get the edges of the shared boundary elements that create the
42687  // shared boundary and store the shared boundary elements from where
42688  // were created
42689  std::map<std::pair<Node*, Node*>, FiniteElement*> halo_edge_element_pt;
42690  std::map<std::pair<Node*, Node*>, FiniteElement*> nonhalo_edge_element_pt;
42691 
42692  // Store the nodes that define the edges
42693  Vector<Node*> halo_edge_nodes_pt;
42694  Vector<Node*> nonhalo_edge_nodes_pt;
42695 
42696  // Go through the shared boundary elements and store their edges
42697  const unsigned nshared_bound_ele = this->nshared_boundary_element(b);
42698  for (unsigned e = 0; e < nshared_bound_ele; e++)
42699  {
42700  // Get the shared boundary element
42701  FiniteElement* current_ele_pt = this->shared_boundary_element_pt(b, e);
42702 
42703  // Get the corner nodes, the first three nodes
42704  Node *first_node_pt = current_ele_pt->node_pt(0);
42705  Node *second_node_pt = current_ele_pt->node_pt(1);
42706  Node *third_node_pt = current_ele_pt->node_pt(2);
42707 
42708  // Check if the elements is halo
42709  if (!current_ele_pt->is_halo())
42710  {
42711  // Store the edges
42712  nonhalo_edge_nodes_pt.push_back(first_node_pt);
42713  nonhalo_edge_nodes_pt.push_back(second_node_pt);
42714 
42715  nonhalo_edge_nodes_pt.push_back(second_node_pt);
42716  nonhalo_edge_nodes_pt.push_back(third_node_pt);
42717 
42718  nonhalo_edge_nodes_pt.push_back(third_node_pt);
42719  nonhalo_edge_nodes_pt.push_back(first_node_pt);
42720 
42721  // Store the info. of the element used to create these edges
42722  std::pair<Node*, Node*> edge1 = std::make_pair(first_node_pt,
42723  second_node_pt);
42724  nonhalo_edge_element_pt[edge1] = current_ele_pt;
42725 
42726  std::pair<Node*, Node*> edge2 = std::make_pair(second_node_pt,
42727  third_node_pt);
42728  nonhalo_edge_element_pt[edge2] = current_ele_pt;
42729 
42730  std::pair<Node*, Node*> edge3 = std::make_pair(third_node_pt,
42731  first_node_pt);
42732  nonhalo_edge_element_pt[edge3] = current_ele_pt;
42733  }
42734  else
42735  {
42736  // Store the edges
42737  halo_edge_nodes_pt.push_back(first_node_pt);
42738  halo_edge_nodes_pt.push_back(second_node_pt);
42739 
42740  halo_edge_nodes_pt.push_back(second_node_pt);
42741  halo_edge_nodes_pt.push_back(third_node_pt);
42742 
42743  halo_edge_nodes_pt.push_back(third_node_pt);
42744  halo_edge_nodes_pt.push_back(first_node_pt);
42745 
42746  // Store the info. of the element used to create these edges
42747  std::pair<Node*, Node*> edge1 = std::make_pair(first_node_pt,
42748  second_node_pt);
42749  halo_edge_element_pt[edge1] = current_ele_pt;
42750 
42751  std::pair<Node*, Node*> edge2 = std::make_pair(second_node_pt,
42752  third_node_pt);
42753  halo_edge_element_pt[edge2] = current_ele_pt;
42754 
42755  std::pair<Node*, Node*> edge3 = std::make_pair(third_node_pt,
42756  first_node_pt);
42757  halo_edge_element_pt[edge3] = current_ele_pt;
42758  }
42759 
42760  } // for (e < nshared_bound_ele)
42761 
42762  // Filter the edges that give rise to a shared boundary
42763 
42764  // Mark the done edges
42765  std::map<std::pair<Node*,Node*>, bool> edge_done;
42766 
42767  // Storage for the edges shared by the elements
42768  Vector<std::pair<Node*, Node*> > unsorted_edges;
42769 
42770  // Storage for the elements that created the unsorted edges (two
42771  // elements, one at each side of the shared boundary)
42772  Vector<Vector<FiniteElement*> > unsorted_edges_elements_pt;
42773 
42774  const unsigned nnonhalo_edge_nodes = nonhalo_edge_nodes_pt.size();
42775  for (unsigned i = 0; i < nnonhalo_edge_nodes; i+=2)
42776  {
42777  Vector<Node*> currenti_edge(2);
42778  currenti_edge[0] = nonhalo_edge_nodes_pt[i];
42779  currenti_edge[1] = nonhalo_edge_nodes_pt[i+1];
42780 
42781  // Create the edge (both nodes that make the edge)
42782  std::pair<Node*, Node*> new_edge =
42783  std::make_pair(currenti_edge[0], currenti_edge[1]);
42784 
42785  if (!edge_done[new_edge])
42786  {
42787  const unsigned nhalo_edge_nodes = halo_edge_nodes_pt.size();
42788  for (unsigned j = 0; j < nhalo_edge_nodes; j+=2)
42789  {
42790  Vector<Node*> currentj_edge(2);
42791  currentj_edge[0] = halo_edge_nodes_pt[j];
42792  currentj_edge[1] = halo_edge_nodes_pt[j+1];
42793 
42794  // Comparing pointer of nodes
42795  if (currenti_edge[0] == currentj_edge[0] &&
42796  currenti_edge[1] == currentj_edge[1])
42797  {
42798  // Store the edge in the proper container
42799  unsorted_edges.push_back(new_edge);
42800 
42801  // Get the elements associated with the edges
42802  Vector<FiniteElement*> tmp_edge_element_pt;
42803 
42804  FiniteElement* nonhalo_ele_pt = nonhalo_edge_element_pt[new_edge];
42805  FiniteElement* halo_ele_pt = halo_edge_element_pt[new_edge];
42806 
42807  tmp_edge_element_pt.push_back(nonhalo_ele_pt);
42808  tmp_edge_element_pt.push_back(halo_ele_pt);
42809 
42810  // Store the elements associated with the edge
42811  unsorted_edges_elements_pt.push_back(tmp_edge_element_pt);
42812 
42813  // Mark the edge as done
42814  edge_done[new_edge] = true;
42815 
42816  // Break the loop for (j < nedge_node)
42817  break;
42818 
42819  } // equal edge
42820 
42821  // Comparing pointer of nodes (reversed)
42822  else if (currenti_edge[0] == currentj_edge[1] &&
42823  currenti_edge[1] == currentj_edge[0])
42824  {
42825  // Create the edge (both nodes that make the edge)
42826  std::pair<Node*, Node*> new_edge =
42827  std::make_pair(currenti_edge[0], currenti_edge[1]);
42828 
42829  // Store the edge in the proper container
42830  unsorted_edges.push_back(new_edge);
42831 
42832  // Create the (reversed) edge (both nodes that make the edge)
42833  std::pair<Node*, Node*> rev_new_edge =
42834  std::make_pair(currentj_edge[0], currentj_edge[1]);
42835 
42836  // Get the elements associated with the edge
42837  Vector<FiniteElement*> tmp_edge_element_pt;
42838 
42839  FiniteElement* nonhalo_ele_pt = nonhalo_edge_element_pt[new_edge];
42840  FiniteElement* halo_ele_pt = halo_edge_element_pt[rev_new_edge];
42841 
42842  tmp_edge_element_pt.push_back(nonhalo_ele_pt);
42843  tmp_edge_element_pt.push_back(halo_ele_pt);
42844 
42845  // Store the elements associated with the edge
42846  unsorted_edges_elements_pt.push_back(tmp_edge_element_pt);
42847 
42848  // Mark the edge as done
42849  edge_done[new_edge] = true;
42850 
42851  // Break the loop for (j < nedge_node)
42852  break;
42853 
42854  } // if (equal edge)
42855 
42856  } // for (j < nhalo_edge_nodes)
42857 
42858  } // if (!edge_done[new_edge])
42859 
42860  } // for (i < nnonhalo_edge_nodes)
42861 
42862  // We already have the edges that make the shared boundary (and the
42863  // elements)
42864  // Sort them to create a contiguous boundary
42865 
42866  // Mark the already sorted edges
42867  std::map<std::pair<Node*,Node*>, bool> edge_sorted;
42868 
42869  const unsigned nunsorted_edges = unsorted_edges.size();
42870 
42871 #ifdef PARANOID
42872  // The number of unsorted edges must be the same as the number of
42873  // shared_boundary element / 2
42874  if (nshared_bound_ele / 2 != nunsorted_edges)
42875  {
42876  std::ostringstream error_message;
42877  error_message
42878  << "The number of shared boundary elements (" << nshared_bound_ele
42879  << ") is not the double\nof the number of unsorted edges ("
42880  << nunsorted_edges << ") for the current boundary ("<< b << ")\n\n";
42881  throw OomphLibError(error_message.str(),
42882  "RefineableTriangleMesh::update_shared_curve_after_restart()",
42883  OOMPH_EXCEPTION_LOCATION);
42884  }
42885 #endif
42886 
42887  unsigned nsorted_edges = 0;
42888 
42889  // Storing for the sorting nodes extracted from the edges, and
42890  // then used to update the polyline
42891  std::list<Node*> sorted_nodes;
42892 
42893  // Storing for the edges elements
42894  std::list<FiniteElement*> sorted_edges_elements_pt;
42895 
42896  // Get the root edge
42897  std::pair<Node*,Node*> edge = unsorted_edges[0];
42898  nsorted_edges++;
42899 
42900  // Mark edge as done
42901  edge_sorted[edge] = true;
42902 
42903  // The initial and final node on the list
42904  Node *first_node_pt = edge.first;
42905  Node *last_node_pt = edge.second;
42906 
42907  // Push back on the list the new edge (nodes)
42908  sorted_nodes.push_back(first_node_pt);
42909  sorted_nodes.push_back(last_node_pt);
42910 
42911  // Store the elements for the current edge
42912  sorted_edges_elements_pt.push_back(unsorted_edges_elements_pt[0][0]);
42913  sorted_edges_elements_pt.push_back(unsorted_edges_elements_pt[0][1]);
42914 
42915  // Iterate while the number of sorted edges be less than the number of
42916  // unsorted edges
42917  while (nsorted_edges < nunsorted_edges)
42918  {
42919  // Flag to indicate when a node was added
42920  bool node_added = false;
42921 
42922  // Start from the next edge since we have already added the
42923  // previous one as the initial edge
42924  for (unsigned iedge = 1; iedge < nunsorted_edges; iedge++)
42925  {
42926  edge = unsorted_edges[iedge];
42927 
42928  // If edge not done
42929  if (!edge_sorted[edge])
42930  {
42931  // Get each individual node
42932  Node* left_node_pt = edge.first;
42933  Node* right_node_pt = edge.second;
42934 
42935  if (left_node_pt == first_node_pt)
42936  {
42937  // Push front the new node
42938  sorted_nodes.push_front(right_node_pt);
42939  first_node_pt = right_node_pt;
42940  node_added = true;
42941 
42942  // Store the elements for the current edge
42943  sorted_edges_elements_pt.push_front(
42944  unsorted_edges_elements_pt[iedge][1]);
42945  sorted_edges_elements_pt.push_front(
42946  unsorted_edges_elements_pt[iedge][0]);
42947  }
42948  else if (left_node_pt == last_node_pt)
42949  {
42950  // Push back the new node
42951  sorted_nodes.push_back(right_node_pt);
42952  last_node_pt = right_node_pt;
42953  node_added = true;
42954 
42955  // Store the elements for the current edge
42956  sorted_edges_elements_pt.push_back(
42957  unsorted_edges_elements_pt[iedge][0]);
42958  sorted_edges_elements_pt.push_back(
42959  unsorted_edges_elements_pt[iedge][1]);
42960  }
42961  else if (right_node_pt == first_node_pt)
42962  {
42963  // Push front the new node
42964  sorted_nodes.push_front(left_node_pt);
42965  first_node_pt = left_node_pt;
42966  node_added = true;
42967 
42968  // Store the elements for the current edge
42969  sorted_edges_elements_pt.push_front(
42970  unsorted_edges_elements_pt[iedge][1]);
42971  sorted_edges_elements_pt.push_front(
42972  unsorted_edges_elements_pt[iedge][0]);
42973  }
42974  else if (right_node_pt == last_node_pt)
42975  {
42976  // Push back the new node
42977  sorted_nodes.push_back(left_node_pt);
42978  last_node_pt = left_node_pt;
42979  node_added = true;
42980 
42981  // Store the elements for the current edge
42982  sorted_edges_elements_pt.push_back(
42983  unsorted_edges_elements_pt[iedge][0]);
42984  sorted_edges_elements_pt.push_back(
42985  unsorted_edges_elements_pt[iedge][1]);
42986  }
42987 
42988  if (node_added)
42989  {
42990  // Mark as done only if one of its nodes has been
42991  // added to the list
42992  edge_sorted[edge] = true;
42993  nsorted_edges++;
42994 
42995  // Break the for
42996  break;
42997  }
42998 
42999  } // if (!edge_done[edge])
43000  } // for (iedge < nunsorted_edges)
43001  } // while (nsorted_edges < nunsorted_edges)
43002 
43003  // At this point we already have a sorted list of nodes, get the
43004  // vertices from them and store them in a vector container
43005 
43006  // Get the number of nodes on the list
43007  unsigned nvertex = sorted_nodes.size();
43008  // The vector to store the vertices (assign space)
43009  Vector<Vector<double> > polyline_vertices(nvertex);
43010 
43011  // Copy the vertices of the nodes
43012  unsigned counter = 0;
43013  for (std::list<Node*>::iterator it_nodes = sorted_nodes.begin();
43014  it_nodes != sorted_nodes.end();
43015  it_nodes++)
43016  {
43017  polyline_vertices[counter].resize(2);
43018  polyline_vertices[counter][0] = (*it_nodes)->x(0);
43019  polyline_vertices[counter][1] = (*it_nodes)->x(1);
43020  counter++;
43021  }
43022 
43023  // Before going to the unrefinement or refinement process check that
43024  // all processors start from the same vertex. Start from the bottom
43025  // left vertex
43026  if (polyline_vertices[nvertex-1][1] < polyline_vertices[0][1])
43027  {
43028  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
43029  }
43030  else if (polyline_vertices[nvertex-1][1] == polyline_vertices[0][1])
43031  {
43032  if (polyline_vertices[nvertex-1][0] < polyline_vertices[0][0])
43033  {
43034  std::reverse(polyline_vertices.begin(), polyline_vertices.end());
43035  }
43036  }
43037 
43038  // Create the polyline associated with this edge
43039  TriangleMeshPolyLine *new_polyline_pt =
43040  new TriangleMeshPolyLine(polyline_vertices, b);
43041 
43042  // Get the curve section representation
43043  TriangleMeshCurveSection *curve_section_pt = vector_polyline_pt[pp];
43044 
43045  // Copy the connection information from the old shared polyline
43046  // to the new one
43047  this->copy_connection_information(curve_section_pt, new_polyline_pt);
43048 
43049  //Now update the polyline according to the new vertices but first
43050  //check if the object is allowed to delete the representation
43051  //or if it should be done by other object
43052  bool delete_it_on_destructor = false;
43053 
43054  // Establish the element as being deleted by the destructor of
43055  // the class
43056  std::set<TriangleMeshCurveSection*>::iterator it =
43057  this->Free_curve_section_pt.find(curve_section_pt);
43058 
43059  if (it!=this->Free_curve_section_pt.end())
43060  {
43061  this->Free_curve_section_pt.erase(it);
43062  delete curve_section_pt;
43063  delete_it_on_destructor = true;
43064  }
43065 
43066  // Copy the new representation
43067  vector_polyline_pt[pp] = new_polyline_pt;
43068 
43069  // Get the new curve section representation
43070  TriangleMeshCurveSection *new_curve_section_pt = vector_polyline_pt[pp];
43071 
43072  // Update the Boundary - Polyline map
43073  this->Boundary_curve_section_pt[b] = new_curve_section_pt;
43074 
43075  if (delete_it_on_destructor)
43076  {
43077  this->Free_curve_section_pt.insert(new_curve_section_pt);
43078  }
43079 
43080  } // for (pp < npoly)
43081 
43082 }
43083 
43084 //===================================================================
43085 // \short Fill the boundary elements structures when dealing with
43086 // shared boundaries that overlap internal boundaries. Document the
43087 // number of elements on the shared boundaries that go to internal
43088 // boundaries
43089 //===================================================================
43090 template <class ELEMENT>
43093 {
43094  // Dummy file
43095  std::ofstream some_file;
43096  fill_boundary_elements_and_nodes_for_internal_boundaries(some_file);
43097 }
43098 
43099 //===================================================================
43100 // \short Fill the boundary elements structures when dealing with
43101 // shared boundaries that overlap internal boundaries
43102 //===================================================================
43103 template <class ELEMENT>
43106  std::ofstream& outfile)
43107 {
43108  // Get the number of processors
43109  const unsigned nproc = this->communicator_pt()->nproc();
43110  // Get the rank of the current processor
43111  unsigned my_rank = this->communicator_pt()->my_rank();
43112 
43113  // Temporal name for the shared boundary overlaps structure
43114  std::map<unsigned, unsigned> shd_bnd_over_int_bnd =
43115  this->Shared_boundary_overlaps_internal_boundary;
43116 
43117  // Register the internal boundary elements that where found to be
43118  // overlapped by shared boundaries
43119  std::set<unsigned> internal_boundary_overlaped;
43120 
43121  // Document the number of elements and nodes associated to the
43122  // boundaries before filling elements and nodes
43123  if (outfile.is_open())
43124  {
43125  const unsigned nbound = this->nboundary();
43126  outfile << "Number of boundaries: " << nbound << "\n\n";
43127  outfile << "Number of elements and nodes associated to each "
43128  << "boundary before\nfilling elements and nodes\n\n";
43129  for (unsigned i = 0; i < nbound; i++)
43130  {
43131  outfile << "Boundary (" << i << ") Elements ("
43132  << this->nboundary_element(i) << ") " << "Nodes ("
43133  << this->nboundary_node(i) << ")\n";
43134  }
43135  }
43136 
43137  // Storage for the shared boundaries in this processor
43138  std::set<unsigned> shared_boundaries_in_this_processor;
43139 
43140  // Get the shared boundaries that this processor has with other
43141  // processors
43142  for (unsigned iproc = 0; iproc < nproc; iproc++)
43143  {
43144  // Work with other processors only
43145  if (iproc != my_rank)
43146  {
43147  // Get the number of boundaries shared with the "iproc"-th processor
43148  unsigned nshared_boundaries_with_iproc =
43149  this->nshared_boundaries(my_rank, iproc);
43150 
43151  if (nshared_boundaries_with_iproc > 0)
43152  {
43153  // Get the boundaries ids shared with "iproc"-th processor
43154  Vector<unsigned> bound_shared_with_iproc;
43155  bound_shared_with_iproc = this->shared_boundaries_ids(my_rank,
43156  iproc);
43157 
43158  // Loop over shared boundaries with "iproc"-th processor
43159  for (unsigned bs = 0; bs < nshared_boundaries_with_iproc; bs++)
43160  {
43161  unsigned bnd_id = bound_shared_with_iproc[bs];
43162  shared_boundaries_in_this_processor.insert(bnd_id);
43163  }
43164  }
43165  }
43166  }
43167 
43168  // ------------------------------------------------------------------
43169  // Copy the boundary elements and nodes from the shared boundary to
43170  // the internal boundary it overlaps
43171  // ------------------------------------------------------------------
43172  // Go through the shared boundaries that overlap internal boundaries
43173  for (std::map<unsigned, unsigned>::iterator it =
43174  shd_bnd_over_int_bnd.begin(); it != shd_bnd_over_int_bnd.end(); it++)
43175  {
43176  // The shared boundary id that overlaps with an internal boundary
43177  const unsigned shd_bnd_id = (*it).first;
43178  // The internal boundary overlapped by the shared boundary
43179  const unsigned int_bnd_id = (*it).second;
43180 
43181  // Check if the shared boundary exist in this processor
43182  std::set<unsigned>::iterator it_set =
43183  shared_boundaries_in_this_processor.find(shd_bnd_id);
43184  if (it_set != shared_boundaries_in_this_processor.end())
43185  {
43186  internal_boundary_overlaped.insert(int_bnd_id);
43187 
43188  // -----------------------------------------------------------------
43189  // First work the nodes of the shared boundaries that should be
43190  // added to the internal boundaries
43191  const unsigned nbnd_node_shd_bnd = this->nboundary_node(shd_bnd_id);
43192 
43193  // Document the number of nodes that will be passed to the internal
43194  // boundary from the current shared boundary
43195  if (outfile.is_open())
43196  {
43197  outfile << "\nPass info. from shared (" << shd_bnd_id
43198  << ") to internal (" << int_bnd_id << ")\n";
43199  outfile << "Number of shared boundary nodes: "
43200  << nbnd_node_shd_bnd << "\n";
43201  }
43202 
43203  for (unsigned in = 0; in < nbnd_node_shd_bnd; in++)
43204  {
43205  // Get the boundary node
43206  Node* bnd_node_pt = this->boundary_node_pt(shd_bnd_id, in);
43207  // Add the node to the internal boundary
43208  this->add_boundary_node(int_bnd_id, bnd_node_pt);
43209  }
43210 
43211  // -----------------------------------------------------------------
43212  // Second work the boundary elements
43213  // Get the number of boundary elements that should be copied to the
43214  // internal boundary
43215  const unsigned nbnd_ele_shd_bnd = this->nboundary_element(shd_bnd_id);
43216 
43217  // Document the number of elements that will be passed to the
43218  // internal boundary from the current shared boundary
43219  if (outfile.is_open())
43220  {
43221  outfile << "Number of shared boundary elements: "
43222  << nbnd_ele_shd_bnd << "\n\n";
43223  }
43224 
43225  // Go through the boundary elements in the shrared boundary and add
43226  // them to the boundary elements of the internal boundary
43227  for (unsigned ie = 0; ie < nbnd_ele_shd_bnd; ie++)
43228  {
43229  // Get the boundary element
43230  FiniteElement* bnd_ele_pt = this->boundary_element_pt(shd_bnd_id, ie);
43231  // Add the element to the boundary elements storage of the
43232  // internal boundary
43233  Boundary_element_pt[int_bnd_id].push_back(bnd_ele_pt);
43234  // Get the face index of the boundary
43235  int face_index = this->face_index_at_boundary(shd_bnd_id, ie);
43236  // Add the face index to the storage of the boundary
43237  Face_index_at_boundary[int_bnd_id].push_back(face_index);
43238 
43239  } // for (ie < nbnd_ele_shd_bnd)
43240 
43241  // If there are regions we need to fill the storage for regions too
43242  const unsigned nregions = this->nregion();
43243  if (nregions > 1)
43244  {
43245  for (unsigned ir = 0 ; ir < nregions; ir++)
43246  {
43247  // Get the region attribute
43248  const unsigned region_id =
43249  static_cast<unsigned>(this->Region_attribute[ir]);
43250 
43251  // Loop over all elements on boundaries in region ir
43252  const unsigned nele_ir = this->nboundary_element_in_region(shd_bnd_id,
43253  region_id);
43254  for (unsigned ier = 0; ier < nele_ir; ier++)
43255  {
43256  // Get the boundary element in current region
43257  FiniteElement* bnd_ele_pt =
43258  this->boundary_element_in_region_pt(shd_bnd_id, region_id, ier);
43259  // Add the boundary element to the internal boundary in the
43260  // region
43261  this->Boundary_region_element_pt[int_bnd_id][region_id].
43262  push_back(bnd_ele_pt);
43263 
43264  // Get the face index of the boundary
43265  int face_index =
43266  this->face_index_at_boundary_in_region(shd_bnd_id, region_id, ier);
43267  // Add the face index to the storage of the boundary region
43268  this->Face_index_region_at_boundary[int_bnd_id][region_id].
43269  push_back(face_index);
43270 
43271  } // for (ier < nele_ir)
43272 
43273  } // for (ir < nregions)
43274 
43275  } // if (nregions > 1)
43276 
43277  } // if (the shared boundary appears in the current processor)
43278 
43279  } // for (loop over the shared bound that overlap an internal bound)
43280 
43281  // Document the number of elements and nodes associated to the
43282  // boundaries after filling elements and nodes
43283  if (outfile.is_open())
43284  {
43285  const unsigned nbound = this->nboundary();
43286  outfile << "Number of boundaries: " << nbound << "\n\n";
43287  outfile << "Number of elements and nodes associated to each "
43288  << "boundary after\nfilling elements and nodes\n\n";
43289  for (unsigned i = 0; i < nbound; i++)
43290  {
43291  outfile << "Boundary (" << i << ") Elements ("
43292  << this->nboundary_element(i) << ")" << " Nodes ("
43293  << this->nboundary_node(i) << ")\n";
43294  }
43295  }
43296 
43297  // ------------------------------------------------------------------
43298  // Finally, re-setup the boundary coordinates for the new nodes on
43299  // the overlaped internal boundaries
43300  // ------------------------------------------------------------------
43301  for (std::set<unsigned>::iterator it = internal_boundary_overlaped.begin();
43302  it != internal_boundary_overlaped.end(); it++)
43303  {
43304  const unsigned overlaped_internal_bnd_id = (*it);
43305 
43306  // Re-setup boundary coordinates
43307  this->template setup_boundary_coordinates<ELEMENT>(overlaped_internal_bnd_id);
43308  }
43309 
43310 }
43311 
43312 #endif // #ifdef OOMPH_HAS_MPI
43313 
43314  //======================================================================
43315  /// Move the boundary nodes onto the boundary defined by the old mesh
43316  //======================================================================
43317  template <class ELEMENT>
43319  RefineableTriangleMesh<ELEMENT>* &new_mesh_pt, const unsigned &b)
43320  {
43321 
43322  // Quick return
43323  if (!Boundary_coordinate_exists[b])
43324  {
43325  return;
43326  }
43327 
43328  //Firstly we set the boundary coordinates of the new nodes
43329  //In case the mapping between the geometric object's intrinsic coordinate
43330  //and the arc-length coordinate is nonlinear. This is only an approximation,
43331  //but it will ensure that the nodes that were input to triangle will
43332  //retain exactly the same boundary coordinates and then linear interpolation
43333  //is used between those values for any newly created nodes.
43334 
43335  // We need to get the boundary nodes from the boundary face
43336  // elements since the "multi_domain" methods add nodes to the
43337  // "Boundary_node_pt" structure which have no boundary coordinates
43338  // assigned
43339  std::set<Node*> tmp_boundary_node_pt;
43340  const unsigned nboundary_ele = this->nboundary_element(b);
43341  for (unsigned e = 0; e < nboundary_ele; e++)
43342  {
43343  // Get the boundary bulk element
43344  FiniteElement* bulk_ele_pt = this->boundary_element_pt(b, e);
43345 #ifdef OOMPH_HAS_MPI
43346  // Only work with nonhalo elements if the mesh is distributed
43347  if (!bulk_ele_pt->is_halo())
43348  {
43349 #endif
43350  // Get the face index
43351  int face_index = this->face_index_at_boundary(b, e);
43352  // Create the face element
43353  FiniteElement* face_ele_pt = new DummyFaceElement<ELEMENT> (
43354  bulk_ele_pt, face_index);
43355 
43356  // Get the number of nodes on the face element
43357  const unsigned nnodes = face_ele_pt->nnode();
43358  for (unsigned i = 0; i < nnodes; i++)
43359  {
43360  // Get the nodes in the face elements
43361  Node* tmp_node_pt = face_ele_pt->node_pt(i);
43362  // Add the nodes to the set of boundary nodes
43363  tmp_boundary_node_pt.insert(tmp_node_pt);
43364  } // for (i < nnodes)
43365 
43366  // Free the memory allocated for the face element
43367  delete face_ele_pt;
43368  face_ele_pt = 0;
43369 #ifdef OOMPH_HAS_MPI
43370  } // if (!bulk_ele_pt->is_halo())
43371 #endif
43372 
43373  } // for (e < nboundary_ele)
43374 
43375  // Get the number of boundary nodes
43376  const unsigned long n_boundary_node = tmp_boundary_node_pt.size();
43377 
43378  // Quick return if there are no nodes
43379  if (n_boundary_node==0)
43380  {
43381 #ifdef OOMPH_HAS_MPI
43382  // Check if we are working with a distributed mesh
43383  if (!this->is_mesh_distributed())
43384  {
43385 #endif
43386  return;
43387 #ifdef OOMPH_HAS_MPI
43388  }
43389  else // The mesh is distributed !!!
43390  {
43391  // Do not forget to participate in the communication
43392  Mesh* face_mesh_pt = new Mesh();
43393  create_unsorted_face_mesh_representation(b, face_mesh_pt);
43394  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(face_mesh_pt);
43395 
43396  //Delete the allocated memory for the geometric object and face mesh
43397  delete mesh_geom_obj_pt;
43398 
43399  // Flush the nodes from the face mesh to make sure we
43400  // don't delete them (the bulk mesh still needs them!)
43401  face_mesh_pt->flush_node_storage();
43402  delete face_mesh_pt;
43403  return;
43404  }
43405 #endif
43406  } // if (n_boundary_node==0)
43407 
43408  //Create a vector of existing boundary nodes with their boundary
43409  //coordinate as the first entry so that we can use standard sort algorithms
43410  Vector<double> node_coord(3);
43411  Vector<double> b_coord(1);
43412 
43413  Vector<Vector<double> > old_boundary_node(n_boundary_node);
43414  unsigned tmp_counter = 0;
43415  for(std::set<Node*>::iterator it_node = tmp_boundary_node_pt.begin();
43416  it_node != tmp_boundary_node_pt.end(); it_node++, tmp_counter++)
43417  {
43418  Node* nod_pt = (*it_node);
43419  nod_pt->get_coordinates_on_boundary(b,b_coord);
43420  node_coord[0] = b_coord[0];
43421  node_coord[1] = nod_pt->x(0);
43422  node_coord[2] = nod_pt->x(1);
43423  old_boundary_node[tmp_counter] = node_coord;
43424  } // for (it_node != tmp_boundary_node_pt.end())
43425 
43426  //Sort the vector
43427  std::sort(old_boundary_node.begin(),old_boundary_node.end());
43428 
43429  //Set up an equivalent ordered vector for the new nodes, based on the
43430  //current coordinate which is the scaled arc-length.
43431  //Also provide storage for the original node index,
43432  //the mapped coordinate and a flag to indicate whether the mapped
43433  //coordinate has been assigned.
43434  //Get the nodes on the boundary but consider to which segment (which
43435  //may appear in a distributed mesh) they belong
43436  Vector<Vector<Node*> > segment_nodes_pt;
43437 
43438 #ifdef OOMPH_HAS_MPI
43439  // Get the number of segments
43440  const unsigned nsegments = new_mesh_pt->nboundary_segment(b);
43441 #else
43442  // The number of segments is one since the boundary is not split
43443  // over multiple processors
43444  const unsigned nsegments = 1;
43445 #endif // #ifdef OOMPH_HAS_MPI
43446 
43447 #ifdef OOMPH_HAS_MPI
43448  // Get the total number of nodes on the boundary
43449  const unsigned n_new_boundary_node = new_mesh_pt->nboundary_segment_node(b);
43450 
43451  // Check if we are working with a distributed mesh
43452  if (this->is_mesh_distributed())
43453  {
43454  // If that is the case we need to ensure that the new mesh has
43455  // nodes too, if that is not the case then return
43456  // Quick return if there are no nodes
43457  if (n_new_boundary_node==0)
43458  {
43459  // Do not forget to participate in the communication
43460  Mesh* face_mesh_pt = new Mesh();
43461  create_unsorted_face_mesh_representation(b, face_mesh_pt);
43462  MeshAsGeomObject* mesh_geom_obj_pt = new MeshAsGeomObject(face_mesh_pt);
43463 
43464  //Delete the allocated memory for the geometric object and face mesh
43465  delete mesh_geom_obj_pt;
43466  // Flush the nodes from the face mesh to make sure we
43467  // don't delete them (the bulk mesh still needs them!)
43468  face_mesh_pt->flush_node_storage();
43469  delete face_mesh_pt;
43470  return;
43471  }
43472  }
43473 #endif // #ifdef OOMPH_HAS_MPI
43474 
43475  //Create a vector of boundary nodes that must be moved
43476  Vector<Vector<unsigned> > nodes_to_be_snapped(nsegments);
43477 
43478  // Go through all the segments to assign the snapped zeta coordinates
43479  // for the new nodes
43480  for (unsigned is = 0; is < nsegments; is++)
43481  {
43482 #ifdef OOMPH_HAS_MPI
43483  const unsigned n_new_boundary_segment_node =
43484  new_mesh_pt->nboundary_segment_node(b,is);
43485 #else
43486  const unsigned n_new_boundary_segment_node = new_mesh_pt->nboundary_node(b);
43487 #endif // #ifdef OOMPH_HAS_MPI
43488 
43489  Vector<Vector<double> > new_boundary_node(n_new_boundary_segment_node);
43490  //There will be six data associated with each node
43491  node_coord.resize(6,0.0);
43492  for(unsigned n = 0; n < n_new_boundary_segment_node; n++)
43493  {
43494 #ifdef OOMPH_HAS_MPI
43495  Node* nod_pt = new_mesh_pt->boundary_segment_node_pt(b,is,n);
43496 #else
43497  Node* nod_pt = new_mesh_pt->boundary_node_pt(b,n);
43498 #endif // #ifdef OOMPH_HAS_MPI
43499  nod_pt->get_coordinates_on_boundary(b,b_coord);
43500  node_coord[0] = b_coord[0];
43501  node_coord[1] = nod_pt->x(0);
43502  node_coord[2] = nod_pt->x(1);
43503  node_coord[3] = n;
43504  new_boundary_node[n] = node_coord;
43505  } // for (n < n_new_boundary_segment_node)
43506 
43507  //Sort the new boundary nodes based on their arc-length coordinate
43508  std::sort(new_boundary_node.begin(),new_boundary_node.end());
43509 
43510  //We now have two sets of nodes ordered by a coordinate that acts in the
43511  //same direction and has the same limits.
43512 
43513  //Loop over the vector of new nodes and allocate exactly the same
43514  //coordinate as the old nodes at points of coincidence
43515  unsigned old_index = 0;
43516  for(unsigned n=0;n<n_new_boundary_segment_node;++n)
43517  {
43518  //Loop over the set of old nodes and if the x and y coordinates
43519  //coincide with the new node copy accross the new boundary coordinate
43520  for(unsigned m=old_index;m<n_boundary_node;++m)
43521  {
43522  if(
43523  (std::fabs(old_boundary_node[m][1]-new_boundary_node[n][1])<1.0e-14)
43524  &&
43525  (std::fabs(old_boundary_node[m][2]-new_boundary_node[n][2])<1.0e-14))
43526  {
43527  //Store the boundary coordinate from the old mesh
43528  new_boundary_node[n][4] = old_boundary_node[m][0];
43529  //Say that it has been stored
43530  new_boundary_node[n][5] = 1.0;
43531  //For efficiency, we can start the iteration from here next
43532  //time round because both vectors are ordered
43533  old_index = m;
43534  break;
43535  }
43536  }
43537  }
43538 
43539  //Check that the end-points have new boundary coordinates allocated
43540 #ifdef PARANOID
43541  if((new_boundary_node[0][5]==0.0) ||
43542  (new_boundary_node[n_new_boundary_segment_node-1][5] == 0.0))
43543  {
43544  std::ostringstream error_stream;
43545  error_stream
43546  <<"New boundary coordinates not found for the first and/or last "
43547  <<"nodes\n"
43548  <<"on the boundary " << b << ". This should not happen because "
43549  <<"these\nlimits should have been setup in the constructor\n";
43550  error_stream
43551  <<"The distance between the new and old nodes is probably outside\n"
43552  <<"our tolerance.\n";
43553  error_stream.precision(20);
43554  error_stream << "Old boundaries: \n";
43555  error_stream <<
43556  old_boundary_node[0][1] << " " << old_boundary_node[0][2]
43557  << " : " <<
43558  old_boundary_node[n_boundary_node-1][1] << " " <<
43559  old_boundary_node[n_boundary_node-1][2] << "\n";
43560  error_stream << "New boundaries: \n" <<
43561  new_boundary_node[0][1] << " " << new_boundary_node[0][2] << " : " <<
43562  new_boundary_node[n_new_boundary_segment_node-1][1] << " " <<
43563  new_boundary_node[n_new_boundary_segment_node-1][2] << "\n";
43564  OomphLibWarning(error_stream.str(),
43565  "RefineableTriangleMesh::snap_nodes_onto_boundary()",
43566  OOMPH_EXCEPTION_LOCATION);
43567  }
43568 #endif
43569 
43570  // This is only true if the boundary is not splitted among the
43571  // processors
43572  if (!this->is_mesh_distributed())
43573  {
43574  //The end points should always be present, so we
43575  //can (and must) always add them in exactly
43576  new_boundary_node[0][4] = new_boundary_node[0][0];
43577 
43578  /// Correct!? Because assigned again below
43579  new_boundary_node[n_new_boundary_segment_node-1][4] =
43580  new_boundary_node[0][5] = 1.0;
43581 
43582  new_boundary_node[n_new_boundary_segment_node-1][4] =
43583  new_boundary_node[n_new_boundary_segment_node-1][0];
43584  new_boundary_node[n_new_boundary_segment_node-1][5] = 1.0;
43585  }
43586 
43587  //Now loop over the interior nodes again and
43588  //use linear interpolation to fill in any unassigned coordiantes
43589  for(unsigned n=1;n<n_new_boundary_segment_node-1;++n)
43590  {
43591  //If the new boundary coordinate has NOT been allocated
43592  if(new_boundary_node[n][5]==0.0)
43593  {
43594  //Add its (unsorted) node number to the list
43595  nodes_to_be_snapped[is].push_back(
43596  static_cast<unsigned>(new_boundary_node[n][3]));
43597 
43598  //We assume that the previous nodal value has been assigned
43599  //and read out the old and new boundary coordinates
43600  double zeta_old_low = new_boundary_node[n-1][0];
43601  double zeta_new_low = new_boundary_node[n-1][4];
43602 
43603  //Loop over the nodes above the current node until
43604  //we find the next one that has been allocated
43605  for(unsigned m=n+1;m<n_new_boundary_segment_node;++m)
43606  {
43607  if(new_boundary_node[m][5]==1.0)
43608  {
43609  //Read out the old boundary coordinate
43610  double zeta_old_high = new_boundary_node[m][0];
43611  double zeta_new_high = new_boundary_node[m][4];
43612  //Use linear interpolation to assign the new boundary coordinate
43613  double frac = (new_boundary_node[n][0] - zeta_old_low)/
43614  (zeta_old_high - zeta_old_low);
43615  new_boundary_node[n][4] = zeta_new_low
43616  + frac*(zeta_new_high - zeta_new_low);
43617  new_boundary_node[n][5] = 1.0;
43618  break;
43619  }
43620  }
43621  }
43622  }
43623 
43624  //Loop over all the nodes and set the new boundary coordinate
43625  for(unsigned n=0;n<n_new_boundary_segment_node;++n)
43626  {
43627  if(new_boundary_node[n][5]==0)
43628  {
43629  throw OomphLibError(
43630  "New boundary coordinate not assigned\n",
43631  "RefineableTriangleMesh::snap_nodes_onto_boundary()",
43632  OOMPH_EXCEPTION_LOCATION);
43633  }
43634 
43635 #ifdef OOMPH_HAS_MPI
43636  //get the old coordinate
43637  new_mesh_pt->boundary_segment_node_pt(
43638  b,is,static_cast<unsigned>(new_boundary_node[n][3]))
43639  ->get_coordinates_on_boundary(b,b_coord);
43640  //Set the new coordinate
43641  b_coord[0] = new_boundary_node[n][4];
43642  new_mesh_pt->boundary_segment_node_pt(
43643  b,is,static_cast<unsigned>(new_boundary_node[n][3]))
43644  ->set_coordinates_on_boundary(b,b_coord);
43645 #else
43646  //get the old coordinate
43647  new_mesh_pt->boundary_node_pt(
43648  b,static_cast<unsigned>(new_boundary_node[n][3]))
43649  ->get_coordinates_on_boundary(b,b_coord);
43650  //Set the new coordinate
43651  b_coord[0] = new_boundary_node[n][4];
43652  new_mesh_pt->boundary_node_pt(
43653  b,static_cast<unsigned>(new_boundary_node[n][3]))
43654  ->set_coordinates_on_boundary(b,b_coord);
43655 #endif // #ifdef OOMPH_HAS_MPI
43656 
43657  }
43658 
43659  } // for (is < nsegments)
43660 
43661  Mesh* face_mesh_pt = new Mesh();
43662  create_unsorted_face_mesh_representation(b, face_mesh_pt);
43663 
43664  //Now that the coordinates have been set up we can do the snapping
43665  MeshAsGeomObject* mesh_geom_obj_pt=new MeshAsGeomObject(face_mesh_pt);
43666 
43667  //Now assign the new nodes positions based on the old meshes
43668  //potentially curvilinear boundary (its geom object incarnation)
43669  Vector<double> new_x(2);
43670 
43671  //Loop over the nodes that need to be snapped
43672  for(unsigned is = 0; is < nsegments; is++)
43673  {
43674  const unsigned nnodes_to_snap = nodes_to_be_snapped[is].size();
43675 
43676  for (unsigned in = 0; in < nnodes_to_snap; in++)
43677  {
43678  //Read out the boundary node number
43679  unsigned n = nodes_to_be_snapped[is][in];
43680 #ifdef OOMPH_HAS_MPI
43681  //Get the boundary coordinate of all new nodes
43682  Node* const nod_pt = new_mesh_pt->boundary_segment_node_pt(b,is,n);
43683 #else
43684  //Get the boundary coordinate of all new nodes
43685  Node* const nod_pt = new_mesh_pt->boundary_node_pt(b,n);
43686 #endif // #ifdef OOMPH_HAS_MPI
43687 
43688  nod_pt->get_coordinates_on_boundary(b,b_coord);
43689  //Let's find boundary coordinates of the new node
43690  mesh_geom_obj_pt->position(b_coord,new_x);
43691 
43692  //Now snap to the boundary
43693  for(unsigned i=0;i<2;i++)
43694  {
43695  nod_pt->x(i) = new_x[i];
43696  }
43697  }
43698  }
43699 
43700  //Delete the allocated memory for the geometric object and face mesh
43701  delete mesh_geom_obj_pt;
43702  // Flush the nodes from the face mesh to make sure we
43703  // don't delete them (the bulk mesh still needs them!)
43704  face_mesh_pt->flush_node_storage();
43705  delete face_mesh_pt;
43706 
43707  //Fix up the elements adjacent to the boundary
43708 
43709  // Dummy six node element for sorting out bubble node for
43710  // seven node enriched quadratic triangles
43711  TElement<2,3> dummy_six_node_element;
43712  for (unsigned j=0;j<6;j++)
43713  {
43714  dummy_six_node_element.construct_node(j);
43715  }
43716 
43717  //This should definitely become a triangular element member function
43718  //Loop over elements
43719  unsigned n_bound_el = new_mesh_pt->nboundary_element(b);
43720  for(unsigned e=0;e<n_bound_el;e++)
43721  {
43722  FiniteElement* el_pt = new_mesh_pt->boundary_element_pt(b,e);
43723 
43724  // Deal with different numbers of nodes separately
43725  unsigned nnod=el_pt->nnode();
43726 
43727 // #ifdef PARANOID
43728 // // Flag to indicate if we successully classified/dealt with the element
43729 // bool success=false;
43730 // #endif
43731 
43732  // Simplex element: Nothing to be done other than error checking
43733  if (nnod==3)
43734  {
43735 #ifdef PARANOID
43736  // Try to cast to a simplex element
43737  TElement<2,2>* t_el_pt=dynamic_cast<TElement<2,2>*>(el_pt);
43738  if (t_el_pt==0)
43739  {
43740  throw OomphLibError(
43741  "Have a three-noded element that's not a TElement<2,2>",
43742  OOMPH_CURRENT_FUNCTION,
43743  OOMPH_EXCEPTION_LOCATION);
43744  }
43745  // If I get there I must not have thrown :)
43746  //success=true;
43747 #endif
43748  }
43749  // Quadratic element (or enriched quadratic)
43750 
43751  else if ((nnod==6)||(nnod==7))
43752  {
43753 
43754 #ifdef PARANOID
43755  // Try to cast to a quadratic element
43756  TElement<2,3>* t_el_pt=dynamic_cast<TElement<2,3>*>(el_pt);
43757  if (t_el_pt==0)
43758  {
43759  if (nnod==6)
43760  {
43761  throw OomphLibError(
43762  "Have a six-noded element that's not a TElement<2,3>",
43763  OOMPH_CURRENT_FUNCTION,
43764  OOMPH_EXCEPTION_LOCATION);
43765  }
43766  else
43767  {
43768  throw OomphLibError(
43769  "Have a seven-noded element that's not a TElement<2,3>",
43770  OOMPH_CURRENT_FUNCTION,
43771  OOMPH_EXCEPTION_LOCATION);
43772  }
43773  }
43774  // If I get there I must not have thrown :)
43775  //success=true;
43776 #endif
43777  // Deal with six noded stuff for all (normal and enriched) elements
43778 
43779  ///----------------------------------------------------------------
43780  /// Repositioning of mid-side nodes
43781  ///----------------------------------------------------------------
43782 
43783  //Side between 0 and 1
43784  if(el_pt->node_pt(3)->is_on_boundary(b))
43785  {
43786  //Make sure that the node I'm about to move is NOT on
43787  //a boundary
43788  if(!el_pt->node_pt(5)->is_on_boundary())
43789  {
43790  //Reset the internal nodes
43791  for(unsigned i=0;i<2;i++)
43792  {
43793  el_pt->node_pt(5)->x(i) =
43794  0.5*(el_pt->node_pt(0)->x(i) + el_pt->node_pt(2)->x(i));
43795  }
43796  }
43797  //Make sure that the node I'm about to move is NOT on
43798  //a boundary
43799  if(!el_pt->node_pt(4)->is_on_boundary())
43800  {
43801  //Reset the internal nodes
43802  for(unsigned i=0;i<2;i++)
43803  {
43804  el_pt->node_pt(4)->x(i) =
43805  0.5*(el_pt->node_pt(1)->x(i) + el_pt->node_pt(2)->x(i));
43806  }
43807  }
43808  }
43809 
43810  //Side between 1 and 2
43811  if(el_pt->node_pt(4)->is_on_boundary(b))
43812  {
43813  //Make sure that the node I'm about to move is NOT on
43814  //a boundary
43815  if(!el_pt->node_pt(5)->is_on_boundary())
43816  {
43817  //Reset the internal nodes
43818  for(unsigned i=0;i<2;i++)
43819  {
43820  el_pt->node_pt(5)->x(i) =
43821  0.5*(el_pt->node_pt(0)->x(i) + el_pt->node_pt(2)->x(i));
43822  }
43823  }
43824  //Make sure that the node I'm about to move is NOT on
43825  //a boundary
43826  if(!el_pt->node_pt(3)->is_on_boundary())
43827  {
43828  //Reset the internal nodes
43829  for(unsigned i=0;i<2;i++)
43830  {
43831  el_pt->node_pt(3)->x(i) =
43832  0.5*(el_pt->node_pt(0)->x(i) + el_pt->node_pt(1)->x(i));
43833  }
43834  }
43835  }
43836 
43837  //Side between 0 and 2
43838  if(el_pt->node_pt(5)->is_on_boundary(b))
43839  {
43840  //Make sure that the node I'm about to move is NOT on
43841  //a boundary
43842  if(!el_pt->node_pt(4)->is_on_boundary())
43843  {
43844  //Reset the internal nodes
43845  for(unsigned i=0;i<2;i++)
43846  {
43847  el_pt->node_pt(4)->x(i) =
43848  0.5*(el_pt->node_pt(1)->x(i) + el_pt->node_pt(2)->x(i));
43849  }
43850  }
43851  //Make sure that the node I'm about to move is NOT on
43852  //a boundary
43853  if(!el_pt->node_pt(3)->is_on_boundary())
43854  {
43855  //Reset the internal nodes
43856  for(unsigned i=0;i<2;i++)
43857  {
43858  el_pt->node_pt(3)->x(i) =
43859  0.5*(el_pt->node_pt(0)->x(i) + el_pt->node_pt(1)->x(i));
43860  }
43861  }
43862  }
43863 
43864  // If it's seven noded it's likely to be an enriched one: Deal with
43865  // the central (bubble) node
43866  if (nnod==7)
43867  {
43868  // Try to cast to an enriched quadratic element
43869  TBubbleEnrichedElement<2,3>* t_el_pt=
43870  dynamic_cast<TBubbleEnrichedElement<2,3>*>(el_pt);
43871  if (t_el_pt==0)
43872  {
43873  throw OomphLibError(
43874  "Have seven-noded element that's not a TBubbleEnrichedElement<2,3>",
43875  OOMPH_CURRENT_FUNCTION,
43876  OOMPH_EXCEPTION_LOCATION);
43877  }
43878 
43879  // Assign the new non-bubble coordinates to the six noded dummy element
43880  for (unsigned j=0;j<6;j++)
43881  {
43882  for (unsigned i=0;i<2;i++)
43883  {
43884  dummy_six_node_element.node_pt(j)->x(i)=el_pt->node_pt(j)->x(i);
43885  }
43886  }
43887 
43888  // Local coordinate of enriched node
43889  unsigned j_enriched=6;
43890  Vector<double> s(2);
43891  el_pt->local_coordinate_of_node(j_enriched,s);
43892 
43893  // Get its position from non-enriched element
43894  Vector<double> x(2);
43895  dummy_six_node_element.interpolated_x(s,x);
43896  el_pt->node_pt(j_enriched)->x(0) = x[0];
43897  el_pt->node_pt(j_enriched)->x(1) = x[1];
43898  }
43899  }
43900  // Any other case cannot be dealt with at the moment
43901 
43902  else
43903  {
43904  std::ostringstream error_stream;
43905  error_stream
43906  << "Cannot deal with this particular " << nnod
43907  << "-noded element yet.\n"
43908  << "Please implement this yourself.\n";
43909  throw OomphLibError(error_stream.str(),
43910 OOMPH_CURRENT_FUNCTION,
43911  OOMPH_EXCEPTION_LOCATION);
43912  }
43913  }
43914 
43915  // Cleanup
43916  for (unsigned j=0;j<6;j++)
43917  {
43918  delete dummy_six_node_element.node_pt(j);
43919  }
43920 
43921  }
43922 
43923 
43924 
43925 #endif // #ifdef OOMPH_HAS_TRIANGLE_LIB
43926 
43927 }
43928 
43929 #endif
oomph::RefineableTriangleMesh::update_open_curve_using_elements_area
bool update_open_curve_using_elements_area(TriangleMeshOpenCurve *&open_curve_pt, const Vector< double > &target_area)
Updates the open curve but using the elements area instead of the default refinement and unrefinement...
Definition: triangle_mesh.template.cc:38363
oomph::RefineableTriangleMesh::create_polylines_from_polyfiles
void create_polylines_from_polyfiles(const std::string &node_file_name, const std::string &poly_file_name)
Helper function to create polylines and fill associate data.
Definition: triangle_mesh.template.cc:36393
oomph::TriangleMesh::compute_boundary_segments_connectivity_and_initial_zeta_values
void compute_boundary_segments_connectivity_and_initial_zeta_values(const unsigned &b)
Compute the boundary segments connectivity for those boundaries that were splited during the distribu...
Definition: triangle_mesh.template.cc:1842
oomph::TriangleMesh::select_boundary_face_elements
void select_boundary_face_elements(Vector< FiniteElement * > &face_el_pt, const unsigned &b, bool &is_internal_boundary, std::map< FiniteElement *, FiniteElement * > &face_to_bulk_element_pt)
Select face element from boundary using the criteria to decide which of the two face elements should ...
Definition: triangle_mesh.template.cc:5241
oomph::RefineableTriangleMesh::reset_halo_haloed_scheme
void reset_halo_haloed_scheme()
In charge of. re-establish the halo(ed) scheme on all processors. Sends info. to create halo elements...
Definition: triangle_mesh.template.cc:15323
oomph::TriangleMesh::get_halo_elements_on_all_procs
void get_halo_elements_on_all_procs(const unsigned &nproc, const Vector< unsigned > &element_domain, const Vector< GeneralisedElement * > &backed_up_el_pt, std::map< Data *, std::set< unsigned > > &processors_associated_with_data, const bool &overrule_keep_as_halo_element_status, std::map< GeneralisedElement *, unsigned > &element_to_global_index, Vector< Vector< Vector< GeneralisedElement * > > > &output_halo_elements_pt)
Creates the halo elements on all processors Gets the halo elements on all processors,...
Definition: triangle_mesh.template.cc:11481
oomph::RefineableTriangleMesh::surface_remesh_for_inner_hole_boundaries
virtual bool surface_remesh_for_inner_hole_boundaries(Vector< Vector< double > > &internal_point_coord, const bool &check_only=false)
Generate a new PSLG representation of the inner hole boundaries. Optional boolean is used to run it a...
Definition: triangle_mesh.template.cc:36204
oomph::classcomp::Tol
static double Tol
Definition: triangle_mesh.template.cc:15033
oomph::RefineableTriangleMesh::restore_polyline_connections_helper
void restore_polyline_connections_helper(TriangleMeshPolyLine *polyline_pt, Vector< TriangleMeshPolyLine * > &resume_initial_connection_polyline_pt, Vector< TriangleMeshPolyLine * > &resume_final_connection_polyline_pt)
Restore the connections of the specific polyline The vertices numbering on the destination boundaries...
Definition: triangle_mesh.template.cc:33008
oomph::RefineableTriangleMesh::sort_nodes_on_shared_boundaries
void sort_nodes_on_shared_boundaries()
Sort the nodes on shared boundaries so that the processors that share a boundary agree with the order...
Definition: triangle_mesh.template.cc:15127
oomph::RefineableTriangleMesh::update_open_curve_after_restart
void update_open_curve_after_restart(TriangleMeshOpenCurve *&open_curve_pt)
Updates the open curve representation after restart.
Definition: triangle_mesh.template.cc:41731
oomph::RefineableTriangleMesh::update_shared_curve_using_elements_area
bool update_shared_curve_using_elements_area(Vector< TriangleMeshPolyLine * > &vector_polyline_pt, const Vector< double > &target_areas)
Updates the polylines using the elements area as constraint for the number of points along the bounda...
Definition: triangle_mesh.template.cc:39607
oomph::TriangleMeshParameters::internal_open_curves_pt
Vector< TriangleMeshOpenCurve * > internal_open_curves_pt() const
Helper function for getting the internal open boundaries.
Definition: triangle_mesh.template.h:167
oomph::RefineableTriangleMesh::snap_nodes_onto_boundary
void snap_nodes_onto_boundary(RefineableTriangleMesh< ELEMENT > *&new_mesh_pt, const unsigned &b)
Snap the boundary nodes onto any curvilinear boundaries.
Definition: triangle_mesh.template.cc:43318
oomph::TriangleMeshParameters::internal_closed_curve_pt
Vector< TriangleMeshClosedCurve * > internal_closed_curve_pt() const
Helper function for getting the internal closed boundaries.
Definition: triangle_mesh.template.h:158
oomph::TriangleMesh::update_holes_information_helper
void update_holes_information_helper(Vector< TriangleMeshPolygon * > &polygons_pt, Vector< Vector< double > > &output_holes_coordinates)
Keeps those vertices that define a hole, those that are inside closed internal boundaries in the new ...
Definition: triangle_mesh.template.cc:10797
oomph::RefineableTriangleMesh::get_required_nodal_information_load_balance_helper
void get_required_nodal_information_load_balance_helper(Vector< Vector< FiniteElement * > > &f_halo_ele_pt, unsigned &iproc, Node *nod_pt)
Helper function to get the required nodal information from an haloed node so that a fully-functional ...
Definition: triangle_mesh.template.cc:26530
oomph::RefineableTriangleMesh::create_new_shared_boundaries
void create_new_shared_boundaries(std::set< FiniteElement * > &element_in_processor_pt, Vector< Vector< FiniteElement * > > &new_shared_boundary_element_pt, Vector< Vector< unsigned > > &new_shared_boundary_element_face_index)
Creates the new shared boundaries, this method is also in charge of computing the shared boundaries i...
Definition: triangle_mesh.template.cc:22462
oomph::RefineableTriangleMesh::fill_boundary_elements_and_nodes_for_internal_boundaries
void fill_boundary_elements_and_nodes_for_internal_boundaries()
Definition: triangle_mesh.template.cc:43092
oomph::TriangleMesh::re_assign_initial_zeta_values_for_internal_boundary
void re_assign_initial_zeta_values_for_internal_boundary(const unsigned &b, Vector< std::list< FiniteElement * > > &old_segment_sorted_ele_pt, std::map< FiniteElement *, bool > &old_is_inverted)
Re-assign the boundary segments initial zeta (arclength) value for those internal boundaries that wer...
Definition: triangle_mesh.template.cc:4059
oomph::RefineableTriangleMesh::get_required_elemental_information_helper
void get_required_elemental_information_helper(unsigned &iproc, FiniteElement *ele_pt)
Helper function to get the required elemental information from an haloed element. This info....
Definition: triangle_mesh.template.cc:17796
oomph::RefineableTriangleMesh::get_required_elemental_information_load_balance_helper
void get_required_elemental_information_load_balance_helper(unsigned &iproc, Vector< Vector< FiniteElement * > > &f_haloed_ele_pt, FiniteElement *ele_pt)
Helper function to get the required elemental information from the element to be sent....
Definition: triangle_mesh.template.cc:26100
oomph::RefineableTriangleMesh::max_element_size
double & max_element_size()
Max element size allowed during adaptation.
Definition: triangle_mesh.template.h:2371
oomph::TriangleMesh::create_tmp_polygons_helper
void create_tmp_polygons_helper(Vector< Vector< TriangleMeshPolyLine * > > &polylines_pt, Vector< TriangleMeshPolygon * > &polygons_pt)
Take the polylines from the shared boundaries and create temporary polygon representations of the dom...
Definition: triangle_mesh.template.cc:8515
oomph::RefineableTriangleMesh::load_balance
void load_balance(const Vector< unsigned > &input_target_domain_for_local_non_halo_element)
Performs the load balancing for unstructured meshes, the load balancing strategy is based on mesh mig...
Definition: triangle_mesh.template.cc:20241
oomph::RefineableTriangleMesh::reset_shared_boundary_elements_and_nodes
void reset_shared_boundary_elements_and_nodes(const bool flush_elements=true, const bool update_elements=true, const bool flush_nodes=true, const bool update_nodes=true)
Re-establish the shared boundary elements after the adaptation process (the updating of shared nodes ...
Definition: triangle_mesh.template.cc:15237
oomph::RefineableTriangleMesh::refine_boundary
bool refine_boundary(Mesh *face_mesh_pt, Vector< Vector< double > > &vector_bnd_vertices, double &refinement_tolerance, const bool &check_only=false)
Helper function that performs the refinement process on the specified boundary by using the provided ...
Definition: triangle_mesh.template.cc:35129
triangle_mesh.template.h
oomph::TriangleMesh::break_loops_on_shared_polyline_helper
void break_loops_on_shared_polyline_helper(const unsigned &initial_shd_bnd_id, std::list< Node * > &input_nodes, Vector< FiniteElement * > &input_boundary_element_pt, Vector< int > &input_face_index_element, const int &input_connect_to_the_left, const int &input_connect_to_the_right, Vector< std::list< Node * > > &output_sorted_nodes_pt, Vector< Vector< FiniteElement * > > &output_boundary_element_pt, Vector< Vector< int > > &output_face_index_element, Vector< int > &output_connect_to_the_left, Vector< int > &output_connect_to_the_right)
Break any possible loop created by the sorted list of nodes that is used to create a new shared polyl...
Definition: triangle_mesh.template.cc:13099
oomph::RefineableTriangleMesh::min_permitted_angle
double & min_permitted_angle()
Min angle before remesh gets triggered.
Definition: triangle_mesh.template.h:2377
oomph::RefineableTriangleMesh::update_other_proc_shd_bnd_node_helper
void update_other_proc_shd_bnd_node_helper(Node *&new_nod_pt, Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, Vector< unsigned > &other_processor_1, Vector< unsigned > &other_processor_2, Vector< unsigned > &other_shared_boundaries, Vector< unsigned > &other_indexes, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function that assigns/updates the references to the node so that it can be found with any othe...
Definition: triangle_mesh.template.cc:20082
oomph::TriangleMeshParameters::disable_automatic_creation_of_vertices_on_boundaries
void disable_automatic_creation_of_vertices_on_boundaries()
Definition: triangle_mesh.template.h:294
oomph::RefineableTriangleMesh::unrefine_shared_boundary_constrained_by_target_area
bool unrefine_shared_boundary_constrained_by_target_area(const unsigned &b, const unsigned &c, Vector< Vector< double > > &vector_bnd_vertices, Vector< double > &area_constraint)
Helper function that performs the unrefinement process on the specified boundary by using the provide...
Definition: triangle_mesh.template.cc:40663
oomph::TriangleMesh::identify_boundary_segments_and_assign_initial_zeta_values
void identify_boundary_segments_and_assign_initial_zeta_values(const unsigned &b, Vector< FiniteElement * > &input_face_ele_pt, const bool &is_internal_boundary, std::map< FiniteElement *, FiniteElement * > &face_to_bulk_element_pt)
Identify the segments from the old mesh (original mesh) in the new mesh (this) and assign initial and...
oomph::RefineableTriangleMesh::add_halo_element_helper
void add_halo_element_helper(unsigned &iproc, FiniteElement *ele_pt)
Helper function to create (halo) elements on the loop process based on the info received in send_and_...
Definition: triangle_mesh.template.cc:18959
oomph::RefineableTriangleMesh::add_haloed_node_helper
void add_haloed_node_helper(unsigned &iproc, Node *nod_pt)
Helper function to add haloed node.
Definition: triangle_mesh.template.cc:18696
oomph::RefineableTriangleMesh::add_element_load_balance_helper
void add_element_load_balance_helper(const unsigned &iproc, Vector< Vector< std::map< unsigned, FiniteElement * > > > &received_old_haloed_element_pt, FiniteElement *ele_pt)
Helper function to create elements on the loop process based on the info received in send_and_receive...
Definition: triangle_mesh.template.cc:27312
oomph::TriangleMeshParameters::set_communicator_pt
void set_communicator_pt(OomphCommunicator *comm_pt)
Function to set communicator (mesh is then assumed to be distributed)
Definition: triangle_mesh.template.h:260
oomph::TriangleMesh::re_scale_re_assigned_initial_zeta_values_for_internal_boundary
void re_scale_re_assigned_initial_zeta_values_for_internal_boundary(const unsigned &b)
Re-scale the re-assigned zeta values for the boundary nodes, apply only for internal boundaries.
Definition: triangle_mesh.template.cc:6442
oomph::RefineableTriangleMesh::update_polygon_after_restart
void update_polygon_after_restart(TriangleMeshPolygon *&polygon_pt)
Updates the polylines representation after restart.
Definition: triangle_mesh.template.cc:40977
oomph::RefineableTriangleMesh::reset_halo_haloed_scheme_helper
void reset_halo_haloed_scheme_helper(Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, Vector< Vector< Node * > > &iproc_currently_created_nodes_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
In charge of creating additional halo(ed) elements on those processors that have no shared boundaries...
Definition: triangle_mesh.template.cc:17459
oomph::RefineableTriangleMesh::update_open_curve_using_face_mesh
bool update_open_curve_using_face_mesh(TriangleMeshOpenCurve *open_polyline_pt, const bool &check_only=false)
Helper function that updates the input open curve by using end-points of elements from FaceMesh(es) t...
Definition: triangle_mesh.template.cc:34362
oomph::RefineableTriangleMesh::create_temporary_boundary_connections
void create_temporary_boundary_connections(Vector< TriangleMeshPolygon * > &tmp_outer_polygons_pt, Vector< TriangleMeshOpenCurve * > &tmp_open_curves_pt)
After unrefinement and refinement has taken place compute the new vertices numbers of the temporary r...
Definition: triangle_mesh.template.cc:32757
oomph::RefineableTriangleMesh::refine_shared_boundary_constrained_by_target_area
bool refine_shared_boundary_constrained_by_target_area(Vector< Vector< double > > &vector_bnd_vertices, Vector< double > &area_constraint)
Helper function that performs the refinement process on the specified boundary by using the provided ...
Definition: triangle_mesh.template.cc:40873
oomph::TriangleMesh::boundary_segment_node_pt
Vector< Vector< Node * > > & boundary_segment_node_pt(const unsigned &b)
Return direct access to nodes associated with a boundary but sorted in segments.
Definition: triangle_mesh.template.h:904
oomph::RefineableTriangleMesh::send_and_receive_elements_nodes_info
void send_and_receive_elements_nodes_info(int &send_proc, int &recv_proc)
Helper function to send back halo and haloed information.
Definition: triangle_mesh.template.cc:18749
oomph::RefineableTriangleMesh::get_boundary_segment_nodes_helper
void get_boundary_segment_nodes_helper(const unsigned &b, Vector< Vector< Node * > > &tmp_segment_nodes)
Get the nodes on the boundary (b), these are stored in the segment they belong (also used by the load...
Definition: triangle_mesh.template.cc:28820
oomph::TriangleMesh::get_element_edges_on_boundary
void get_element_edges_on_boundary(std::map< std::pair< Node *, Node * >, unsigned > &element_edges_on_boundary)
Get the element edges (pair of nodes, edges) that lie on a boundary (used to mark shared boundaries t...
Definition: triangle_mesh.template.cc:11570
oomph::TriangleMesh::Point::x
coord_t x
Definition: triangle_mesh.template.h:2097
oomph::RefineableTriangleMesh::adapt
void adapt(const Vector< double > &elem_error)
Adapt mesh, based on elemental error provided.
Definition: triangle_mesh.template.cc:29344
oomph::TriangleMesh::reset_boundary_element_info
virtual void reset_boundary_element_info(Vector< unsigned > &ntmp_boundary_elements, Vector< Vector< unsigned > > &ntmp_boundary_elements_in_region, Vector< FiniteElement * > &deleted_elements)
Reset the boundary elements info. after load balance have taken place.
Definition: triangle_mesh.template.cc:14687
oomph::TriangleMesh::create_polylines_from_halo_elements_helper
void create_polylines_from_halo_elements_helper(const Vector< unsigned > &element_domain, std::map< GeneralisedElement *, unsigned > &element_to_global_index, std::set< FiniteElement * > &element_in_processor_pt, Vector< Vector< Vector< GeneralisedElement * > > > &input_halo_elements, std::map< std::pair< Node *, Node * >, unsigned > &elements_edges_on_boundary, Vector< Vector< Vector< TriangleMeshPolyLine * > > > &output_polylines_pt)
Creates polylines from the intersection of halo elements on all processors. The new polylines define ...
Definition: triangle_mesh.template.cc:11636
oomph::TriangleMesh::Point::y
coord_t y
Definition: triangle_mesh.template.h:2097
oomph::RefineableTriangleMesh::apply_max_length_constraint
bool apply_max_length_constraint(Mesh *face_mesh_pt, Vector< Vector< double > > &vector_bnd_vertices, double &max_length_constraint)
Definition: triangle_mesh.template.cc:35279
oomph::RefineableTriangleMesh::add_received_node_load_balance_helper
void add_received_node_load_balance_helper(Node *&new_nod_pt, Vector< Vector< FiniteElement * > > &f_haloed_ele_pt, Vector< Vector< std::map< unsigned, FiniteElement * > > > &received_old_haloed_element_pt, Vector< Node * > &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, unsigned &iproc, unsigned &node_index, FiniteElement *const &new_el_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function to add a new node from load balance.
Definition: triangle_mesh.template.cc:27577
oomph::TriangleMesh::output_boundary_coordinates
void output_boundary_coordinates(const unsigned &b, std::ostream &outfile)
Definition: triangle_mesh.template.cc:7902
oomph::RefineableTriangleMesh::create_sorted_face_mesh_representation
void create_sorted_face_mesh_representation(const unsigned &boundary_id, Mesh *face_mesh_pt, std::map< FiniteElement *, bool > &is_inverted, bool &inverted_face_mesh)
Helper function Creates a sorted face mesh representation of the specified PolyLine It means that the...
Definition: triangle_mesh.template.cc:35434
oomph::RefineableTriangleMesh
Unstructured refineable Triangle Mesh.
Definition: triangle_mesh.template.h:2154
oomph::RefineableTriangleMesh::resume_boundary_connections
void resume_boundary_connections(Vector< TriangleMeshPolyLine * > &resume_initial_connection_polyline_pt, Vector< TriangleMeshPolyLine * > &resume_final_connection_polyline_pt)
Resume the boundary connections that may have been suspended because the destination boundary is no p...
Definition: triangle_mesh.template.cc:33774
oomph::RefineableTriangleMesh::min_element_size
double & min_element_size()
Min element size allowed during adaptation.
Definition: triangle_mesh.template.h:2374
oomph::TriangleMesh::break_loops_on_shared_polyline_load_balance_helper
void break_loops_on_shared_polyline_load_balance_helper(const unsigned &initial_shd_bnd_id, std::list< Node * > &input_nodes, Vector< FiniteElement * > &input_boundary_element_pt, Vector< FiniteElement * > &input_boundary_face_element_pt, Vector< int > &input_face_index_element, const int &input_connect_to_the_left, const int &input_connect_to_the_right, Vector< std::list< Node * > > &output_sorted_nodes_pt, Vector< Vector< FiniteElement * > > &output_boundary_element_pt, Vector< Vector< FiniteElement * > > &output_boundary_face_element_pt, Vector< Vector< int > > &output_face_index_element, Vector< int > &output_connect_to_the_left, Vector< int > &output_connect_to_the_right)
Break any possible loop created by the sorted list of nodes that is used to create a new shared polyl...
Definition: triangle_mesh.template.cc:14019
oomph::RefineableTriangleMesh::get_shared_boundary_segment_nodes_helper
void get_shared_boundary_segment_nodes_helper(const unsigned &shd_bnd_id, Vector< Vector< Node * > > &tmp_segment_nodes)
Get the nodes on the shared boundary (b), these are stored in the segment they belong.
Definition: triangle_mesh.template.cc:25773
oomph::TriangleMeshParameters::regions_coordinates
std::map< unsigned, Vector< double > > & regions_coordinates()
Helper function for getting access to the regions coordinates.
Definition: triangle_mesh.template.h:230
oomph::RefineableTriangleMesh::construct_new_node_load_balance_helper
void construct_new_node_load_balance_helper(Node *&new_nod_pt, Vector< Vector< FiniteElement * > > &f_haloed_ele_pt, Vector< Vector< std::map< unsigned, FiniteElement * > > > &received_old_haloed_element_pt, Vector< Node * > &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, unsigned &iproc, unsigned &node_index, FiniteElement *const &new_el_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function which constructs a new node (on an element) with the information sent from the load b...
Definition: triangle_mesh.template.cc:27648
oomph::TriangleMesh::dump_distributed_info_for_restart
void dump_distributed_info_for_restart(std::ostream &dump_file)
Used to dump info. related with distributed triangle meshes.
Definition: triangle_mesh.template.cc:7319
oomph::TriangleMeshParameters
Helper object for dealing with the parameters used for the TriangleMesh objects.
Definition: triangle_mesh.template.h:96
oomph::RefineableTriangleMesh::update_polygon_using_face_mesh
bool update_polygon_using_face_mesh(TriangleMeshPolygon *polygon_pt, const bool &check_only=false)
Helper function that updates the input polygon's PSLG by using the end-points of elements from FaceMe...
Definition: triangle_mesh.template.cc:33876
oomph::RefineableTriangleMesh::add_halo_node_helper
void add_halo_node_helper(Node *&new_nod_pt, Vector< Node * > &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, unsigned &iproc, unsigned &node_index, FiniteElement *const &new_el_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function to add halo node.
Definition: triangle_mesh.template.cc:19128
oomph::TriangleMesh::build_from_scaffold
void build_from_scaffold(TimeStepper *time_stepper_pt, const bool &use_attributes)
Build mesh from scaffold.
Definition: triangle_mesh.template.cc:45
oomph::TriangleMesh::shared_boundary_overlaps_internal_boundary
const bool shared_boundary_overlaps_internal_boundary(const unsigned &shd_bnd_id)
Checks if the shared boundary overlaps an internal boundary.
Definition: triangle_mesh.template.h:1661
oomph::TriangleMesh::sort_polylines_helper
void sort_polylines_helper(Vector< TriangleMeshPolyLine * > &unsorted_polylines_pt, Vector< Vector< TriangleMeshPolyLine * > > &sorted_polylines_pt)
Sorts the polylines so they be continuous and then we can create a closed or open curve from them.
Definition: triangle_mesh.template.cc:11213
oomph::RefineableSolidTriangleMesh
Unstructured refineable Triangle Mesh upgraded to solid mesh.
Definition: triangle_mesh.template.h:3820
oomph::RefineableTriangleMesh::create_halo_element
void create_halo_element(unsigned &iproc, Vector< Node * > &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function to create (halo) elements on the loop process based on the info received in send_and_...
Definition: triangle_mesh.template.cc:18867
oomph::TriangleMesh::oomph_vertex_nodes_id
Vector< unsigned > oomph_vertex_nodes_id()
Return the vector that contains the oomph-lib node number for all vertex nodes in the TriangulateIO r...
Definition: triangle_mesh.template.h:1118
oomph
Definition: annular_domain.h:34
oomph::RefineableTriangleMesh::compute_shared_node_degree_helper
void compute_shared_node_degree_helper(Vector< Vector< FiniteElement * > > &unsorted_face_ele_pt, std::map< Node *, unsigned > &global_node_degree)
Computes the degree of the nodes on the shared boundaries, the degree of the node is computed from th...
Definition: triangle_mesh.template.cc:24589
oomph::RefineableTriangleMesh::get_required_nodal_information_helper
void get_required_nodal_information_helper(unsigned &iproc, Node *nod_pt)
Helper function to get the required nodal information from a haloed node so that a fully-functional h...
Definition: triangle_mesh.template.cc:18117
oomph::RefineableTriangleMesh::get_face_mesh_representation
void get_face_mesh_representation(TriangleMeshPolygon *polygon_pt, Vector< Mesh * > &face_mesh_pt)
Helper function to construct face mesh representation of all polylines, possibly with segments re-dis...
Definition: triangle_mesh.template.cc:35631
oomph::TriangleMeshParameters::element_area
double element_area() const
Helper function for getting the element area.
Definition: triangle_mesh.template.h:176
oomph::TriangleMesh::build_triangulateio
void build_triangulateio(const std::string &poly_file_name, TriangulateIO &triangulate_io, bool &use_attributes)
Helper function to create TriangulateIO object (return in triangulate_io) from the ....
Definition: triangle_mesh.template.cc:7079
oomph::TriangleMesh::compute_holes_left_by_halo_elements_helper
void compute_holes_left_by_halo_elements_helper(Vector< Vector< double > > &output_holes_coordinates)
Compute the holes left by the halo elements, those adjacent to the shared boundaries.
Definition: triangle_mesh.template.cc:10686
oomph::classcomp::operator()
bool operator()(const std::pair< double, double > &lhs, const std::pair< double, double > &rhs) const
Definition: triangle_mesh.template.cc:15037
oomph::TriangleMesh::synchronize_boundary_coordinates
void synchronize_boundary_coordinates(const unsigned &b)
In charge of sinchronize the boundary coordinates for internal boundaries that were split as part of ...
Definition: triangle_mesh.template.cc:5580
oomph::TriangleMesh::set_mesh_level_time_stepper
void set_mesh_level_time_stepper(TimeStepper *const &time_stepper_pt, const bool &preserve_existing_data)
Overload set_mesh_level_time_stepper so that the stored time stepper now corresponds to the new times...
Definition: triangle_mesh.template.h:845
oomph::RefineableTriangleMesh::create_adjacency_matrix_new_shared_edges_helper
void create_adjacency_matrix_new_shared_edges_helper(Vector< Vector< FiniteElement * > > &unsorted_face_ele_pt, Vector< Vector< Node * > > &tmp_sorted_shared_node_pt, std::map< Node *, Vector< Vector< unsigned > > > &node_alias, Vector< Vector< Vector< unsigned > > > &adjacency_matrix)
Sort the nodes on the new shared boundaries (after load balancing), computes the alias of the nodes a...
Definition: triangle_mesh.template.cc:25587
oomph::TriangleMeshParameters::enable_use_attributes
void enable_use_attributes()
Helper function for enabling the use of attributes.
Definition: triangle_mesh.template.h:244
oomph::RefineableTriangleMesh::refine_triangulateio
void refine_triangulateio(TriangulateIO &triangulate_io, const Vector< double > &target_area, TriangulateIO &triangle_refine)
Build a new TriangulateIO object from previous TriangulateIO based on target area for each element.
Definition: triangle_mesh.template.cc:14882
oomph::TriangleMesh::create_shared_polyline
void create_shared_polyline(const unsigned &my_rank, const unsigned &shd_bnd_id, const unsigned &iproc, const unsigned &jproc, std::list< Node * > &sorted_nodes, const int &root_edge_bnd_id, Vector< FiniteElement * > &bulk_bnd_ele_pt, Vector< int > &face_index_ele, Vector< Vector< TriangleMeshPolyLine * > > &unsorted_polylines_pt, const int &connect_to_the_left_flag, const int &connect_to_the_right_flag)
Create the shared polyline and fill the data structured that keep all the information associated with...
Definition: triangle_mesh.template.cc:14444
oomph::RefineableTriangleMesh::compute_global_node_names_and_shared_nodes
void compute_global_node_names_and_shared_nodes(Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Compute the names of the nodes on shared boundaries in this (my_rank) processor with other processors...
Definition: triangle_mesh.template.cc:15894
oomph::RefineableTriangleMesh::update_shared_curve_after_restart
void update_shared_curve_after_restart(Vector< TriangleMeshPolyLine * > &vector_polyline_pt)
Updates the shared polylines representation after restart.
Definition: triangle_mesh.template.cc:42676
oomph::TriangleMesh::create_shared_polylines_connections
void create_shared_polylines_connections()
Establish the connections of the polylines previously marked as having connections....
Definition: triangle_mesh.template.cc:9384
oomph::TriangleMesh::shared_boundaries_ids
Vector< Vector< Vector< unsigned > > > shared_boundaries_ids() const
Definition: triangle_mesh.template.h:1388
oomph::RefineableTriangleMesh::synchronize_shared_boundary_connections
const void synchronize_shared_boundary_connections()
Synchronise the vertices that are marked for non deletion.
Definition: triangle_mesh.template.cc:32408
oomph::RefineableTriangleMesh::send_boundary_node_info_of_shared_nodes
void send_boundary_node_info_of_shared_nodes(Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Get the original boundaries to which is associated each shared node, and send the info....
Definition: triangle_mesh.template.cc:16894
oomph::RefineableTriangleMesh::create_unsorted_face_mesh_representation
void create_unsorted_face_mesh_representation(const unsigned &boundary_id, Mesh *face_mesh_pt)
Helper function Creates an unsorted face mesh representation from the specified boundary id....
Definition: triangle_mesh.template.cc:35397
oomph::RefineableTriangleMesh::refine_boundary_constrained_by_target_area
bool refine_boundary_constrained_by_target_area(MeshAsGeomObject *mesh_geom_obj_pt, Vector< Vector< double > > &vector_bnd_vertices, double &refinement_tolerance, Vector< double > &area_constraint)
Helper function that performs the refinement process on the specified boundary by using the provided ...
Definition: triangle_mesh.template.cc:40519
oomph::RefineableTriangleMesh::add_non_delete_vertices_from_boundary_helper
void add_non_delete_vertices_from_boundary_helper(Vector< Vector< Node * > > src_bound_segment_node_pt, Vector< Vector< Node * > > dst_bound_segment_node_pt, const unsigned &dst_bnd_id, const unsigned &dst_bnd_chunk)
Adds the vertices from the sources boundary that are repeated in the destination boundary to the list...
Definition: triangle_mesh.template.cc:32321
oomph::Bottom_left_sorter
struct oomph::classcomp Bottom_left_sorter
oomph::RefineableTriangleMesh::get_shared_boundary_elements_and_face_indexes
void get_shared_boundary_elements_and_face_indexes(const Vector< FiniteElement * > &first_element_pt, const Vector< FiniteElement * > &second_element_pt, Vector< FiniteElement * > &first_shared_boundary_element_pt, Vector< unsigned > &first_shared_boundary_element_face_index, Vector< FiniteElement * > &second_shared_boundary_element_pt, Vector< unsigned > &second_shared_boundary_element_face_index)
Use the first and second group of elements to find the intersection between them to get the shared bo...
Definition: triangle_mesh.template.cc:22307
oomph::RefineableTriangleMesh::add_node_load_balance_helper
void add_node_load_balance_helper(unsigned &iproc, Vector< Vector< FiniteElement * > > &f_halo_ele_pt, Vector< Node * > &new_nodes_on_domain, Node *nod_pt)
Helper function to add haloed node.
Definition: triangle_mesh.template.cc:26471
oomph::RefineableTriangleMesh::construct_new_halo_node_helper
void construct_new_halo_node_helper(Node *&new_nod_pt, Vector< Node * > &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, unsigned &iproc, unsigned &node_index, FiniteElement *const &new_el_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function which constructs a new halo node (on an element) with the information sent from the h...
Definition: triangle_mesh.template.cc:19183
oomph::TriangleMesh::create_shared_boundaries
void create_shared_boundaries(OomphCommunicator *comm_pt, const Vector< unsigned > &element_domain, const Vector< GeneralisedElement * > &backed_up_el_pt, const Vector< FiniteElement * > &backed_up_f_el_pt, std::map< Data *, std::set< unsigned > > &processors_associated_with_data, const bool &overrule_keep_as_halo_element_status)
Creates the shared boundaries.
Definition: triangle_mesh.template.cc:11406
oomph::RefineableTriangleMesh::create_element_load_balance_helper
void create_element_load_balance_helper(unsigned &iproc, Vector< Vector< FiniteElement * > > &f_haloed_ele_pt, Vector< Vector< std::map< unsigned, FiniteElement * > > > &received_old_haloed_element_pt, Vector< FiniteElement * > &new_elements_on_domain, Vector< Node * > &new_nodes_on_domain, Vector< Vector< Vector< std::map< unsigned, Node * > > > > &other_proc_shd_bnd_node_pt, Vector< Vector< Vector< unsigned > > > &global_node_names, std::map< Vector< unsigned >, unsigned > &node_name_to_global_index, Vector< Node * > &global_shared_node_pt)
Helper function to create elements on the loop process based on the info received in send_and_receive...
Definition: triangle_mesh.template.cc:27227
oomph::RefineableTriangleMesh::unrefine_boundary
bool unrefine_boundary(const unsigned &b, const unsigned &c, Vector< Vector< double > > &vector_bnd_vertices, double &unrefinement_tolerance, const bool &check_only=false)
Helper function that performs the unrefinement process.
Definition: triangle_mesh.template.cc:34844
oomph::TriangleMesh
Definition: triangle_mesh.template.h:365
oomph::classcomp
Definition: triangle_mesh.template.cc:15029
oomph::RefineableTriangleMesh::restore_boundary_connections
void restore_boundary_connections(Vector< TriangleMeshPolyLine * > &resume_initial_connection_polyline_pt, Vector< TriangleMeshPolyLine * > &resume_final_connection_polyline_pt)
After unrefinement and refinement has taken place compute the new vertices numbers of the boundaries ...
Definition: triangle_mesh.template.cc:32884
oomph::TriangleMesh::read_distributed_info_for_restart
void read_distributed_info_for_restart(std::istream &restart_file)
Used to read info. related with distributed triangle meshes.
Definition: triangle_mesh.template.cc:7566
oomph::TriangleMesh::check_connections_of_polyline_nodes
const int check_connections_of_polyline_nodes(std::set< FiniteElement * > &element_in_processor_pt, const int &root_edge_bnd_id, std::map< std::pair< Node *, Node * >, bool > &overlapped_face, std::map< unsigned, std::map< Node *, bool > > &node_on_bnd_not_overlapped_by_shd_bnd, std::list< Node * > &current_polyline_nodes, std::map< unsigned, std::list< Node * > > &shared_bnd_id_to_sorted_list_node_pt, const unsigned &node_degree, Node *&new_node_pt, const bool called_from_load_balance=false)
Check for any possible connections that the array of sorted nodes have with any previous boundaries o...
Definition: triangle_mesh.template.cc:8945
oomph::TriangleMesh::create_distributed_domain_representation
void create_distributed_domain_representation(Vector< TriangleMeshPolygon * > &polygons_pt, Vector< TriangleMeshOpenCurve * > &open_curves_pt)
Creates the distributed domain representation. Joins the original boundaires, shared boundaries and c...
Definition: triangle_mesh.template.cc:8017
oomph::RefineableTriangleMesh::update_polygon_using_elements_area
bool update_polygon_using_elements_area(TriangleMeshPolygon *&polygon_pt, const Vector< double > &target_area)
Updates the polylines using the elements area as constraint for the number of points along the bounda...
Definition: triangle_mesh.template.cc:37421
oomph::RefineableTriangleMesh::get_connected_vertex_number_on_dst_boundary
bool get_connected_vertex_number_on_dst_boundary(Vector< double > &vertex_coordinates, const unsigned &dst_b_id, unsigned &vertex_number)
Computes the associated vertex number on the destination boundary.
Definition: triangle_mesh.template.cc:33820
oomph::RefineableTriangleMesh::add_vertices_for_non_deletion
void add_vertices_for_non_deletion()
Mark the vertices that are not allowed for deletion by the unrefienment/refinement polyline methods....
Definition: triangle_mesh.template.cc:31598
oomph::TriangleMesh::Point
Definition: triangle_mesh.template.h:2096
oomph::RefineableTriangleMesh::unrefine_boundary_constrained_by_target_area
bool unrefine_boundary_constrained_by_target_area(const unsigned &b, const unsigned &c, Vector< Vector< double > > &vector_bnd_vertices, double &unrefinement_tolerance, Vector< double > &area_constraint)
Helper function that performs the unrefinement process on the specified boundary by using the provide...
Definition: triangle_mesh.template.cc:40264
oomph::TriangleMeshParameters::extra_holes_coordinates
Vector< Vector< double > > extra_holes_coordinates() const
Helper function for getting the extra holes.
Definition: triangle_mesh.template.h:182
oomph::TriangleMesh::create_tmp_open_curves_helper
void create_tmp_open_curves_helper(Vector< Vector< TriangleMeshPolyLine * > > &sorted_open_curves_pt, Vector< TriangleMeshPolyLine * > &unsorted_shared_to_internal_poly_pt, Vector< TriangleMeshOpenCurve * > &open_curves_pt)
Take the polylines from the original open curves and created new temporaly representations of open cu...
Definition: triangle_mesh.template.cc:8904